summaryrefslogtreecommitdiffstats
path: root/compiler
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:11:38 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:12:43 +0000
commitcf94bdc0742c13e2a0cac864c478b8626b266e1b (patch)
tree044670aa50cc5e2b4229aa0b6b3df6676730c0a6 /compiler
parentAdding debian version 1.65.0+dfsg1-2. (diff)
downloadrustc-cf94bdc0742c13e2a0cac864c478b8626b266e1b.tar.xz
rustc-cf94bdc0742c13e2a0cac864c478b8626b266e1b.zip
Merging upstream version 1.66.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc/src/main.rs4
-rw-r--r--compiler/rustc_ast/Cargo.toml1
-rw-r--r--compiler/rustc_ast/src/ast.rs43
-rw-r--r--compiler/rustc_ast/src/lib.rs2
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs17
-rw-r--r--compiler/rustc_ast/src/token.rs49
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs150
-rw-r--r--compiler/rustc_ast/src/util/parser.rs4
-rw-r--r--compiler/rustc_ast/src/visit.rs24
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs23
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs236
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs87
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs22
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs99
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs158
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs10
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs127
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs127
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs291
-rw-r--r--compiler/rustc_ast_passes/src/lib.rs1
-rw-r--r--compiler/rustc_ast_pretty/Cargo.toml1
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs14
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs2
-rw-r--r--compiler/rustc_attr/Cargo.toml1
-rw-r--r--compiler/rustc_attr/src/lib.rs1
-rw-r--r--compiler/rustc_attr/src/session_diagnostics.rs161
-rw-r--r--compiler/rustc_borrowck/Cargo.toml1
-rw-r--r--compiler/rustc_borrowck/src/constraint_generation.rs12
-rw-r--r--compiler/rustc_borrowck/src/consumers.rs9
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs152
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs148
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs156
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs16
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs5
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs12
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs109
-rw-r--r--compiler/rustc_borrowck/src/lib.rs22
-rw-r--r--compiler/rustc_borrowck/src/nll.rs14
-rw-r--r--compiler/rustc_borrowck/src/places_conflict.rs13
-rw-r--r--compiler/rustc_borrowck/src/prefixes.rs1
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs41
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs374
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs32
-rw-r--r--compiler/rustc_borrowck/src/session_diagnostics.rs71
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs17
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs17
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs39
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs156
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs19
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs10
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs24
-rw-r--r--compiler/rustc_builtin_macros/src/cfg.rs10
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs73
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/bounds.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/debug.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/decodable.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs20
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/encodable.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs13
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/hash.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs1949
-rw-r--r--compiler/rustc_builtin_macros/src/format/ast.rs240
-rw-r--r--compiler/rustc_builtin_macros/src/format/expand.rs353
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs39
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs15
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/main.yml99
-rw-r--r--compiler/rustc_codegen_cranelift/.vscode/settings.json6
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock62
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml14
-rw-r--r--compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock38
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs52
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/abi_checker.rs60
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/build_backend.rs16
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs13
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/config.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/mod.rs21
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/prepare.rs186
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/rustc_info.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/tests.rs179
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/utils.rs46
-rwxr-xr-xcompiler/rustc_codegen_cranelift/clean_all.sh6
-rw-r--r--compiler/rustc_codegen_cranelift/config.txt2
-rw-r--r--compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/example/std_example.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch29
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0001-abi-checker-Disable-failing-tests.patch36
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch96
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch47
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh6
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh8
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs53
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/allocator.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/archive.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs26
-rw-r--r--compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs17
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs112
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/jit.rs51
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs22
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs62
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs128
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs14
-rw-r--r--compiler/rustc_codegen_cranelift/src/main_shim.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/num.rs61
-rw-r--r--compiler/rustc_codegen_cranelift/src/unsize.rs40
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs56
-rw-r--r--compiler/rustc_codegen_cranelift/src/vtable.rs26
-rw-r--r--compiler/rustc_codegen_gcc/src/abi.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/archive.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs5
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs37
-rw-r--r--compiler/rustc_codegen_gcc/src/consts.rs6
-rw-r--r--compiler/rustc_codegen_gcc/src/context.rs24
-rw-r--r--compiler/rustc_codegen_gcc/src/errors.rs242
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs19
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/simd.rs204
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs17
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/asm.rs9
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/int.rs2
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml3
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs67
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs99
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs261
-rw-r--r--compiler/rustc_codegen_llvm/src/base.rs13
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs56
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs26
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs12
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs52
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs110
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs36
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs241
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs151
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs63
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs112
-rw-r--r--compiler/rustc_codegen_ssa/src/common.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs356
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs104
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs20
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs16
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs28
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs208
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/abi.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/intrinsic.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/misc.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/write.rs1
-rw-r--r--compiler/rustc_const_eval/Cargo.toml1
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs78
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs52
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs16
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs8
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs4
-rw-r--r--compiler/rustc_const_eval/src/errors.rs104
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs108
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs25
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs14
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs75
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs25
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs9
-rw-r--r--compiler/rustc_const_eval/src/lib.rs10
-rw-r--r--compiler/rustc_const_eval/src/might_permit_raw_init.rs44
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs81
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs20
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs12
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs64
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/resolver.rs6
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs9
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs45
-rw-r--r--compiler/rustc_const_eval/src/util/might_permit_raw_init.rs151
-rw-r--r--compiler/rustc_const_eval/src/util/mod.rs2
-rw-r--r--compiler/rustc_data_structures/Cargo.toml1
-rw-r--r--compiler/rustc_data_structures/src/flock/linux.rs7
-rw-r--r--compiler/rustc_data_structures/src/graph/vec_graph/mod.rs4
-rw-r--r--compiler/rustc_data_structures/src/lib.rs3
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/mod.rs37
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/tests.rs8
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs64
-rw-r--r--compiler/rustc_data_structures/src/sorted_map.rs17
-rw-r--r--compiler/rustc_data_structures/src/sso/set.rs2
-rw-r--r--compiler/rustc_data_structures/src/transitive_relation.rs12
-rw-r--r--compiler/rustc_data_structures/src/unord.rs382
-rw-r--r--compiler/rustc_driver/Cargo.toml2
-rw-r--r--compiler/rustc_driver/src/lib.rs61
-rw-r--r--compiler/rustc_driver/src/pretty.rs4
-rw-r--r--compiler/rustc_driver/src/session_diagnostics.rs30
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0045.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0092.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0094.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0161.md7
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0210.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0211.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0311.md42
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0579.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0591.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0622.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0732.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0743.md2
-rw-r--r--compiler/rustc_error_messages/Cargo.toml1
-rw-r--r--compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl4
-rw-r--r--compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl68
-rw-r--r--compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl121
-rw-r--r--compiler/rustc_error_messages/locales/en-US/compiletest.ftl5
-rw-r--r--compiler/rustc_error_messages/locales/en-US/errors.ftl13
-rw-r--r--compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl (renamed from compiler/rustc_error_messages/locales/en-US/typeck.ftl)83
-rw-r--r--compiler/rustc_error_messages/locales/en-US/infer.ftl4
-rw-r--r--compiler/rustc_error_messages/locales/en-US/lint.ftl7
-rw-r--r--compiler/rustc_error_messages/locales/en-US/metadata.ftl2
-rw-r--r--compiler/rustc_error_messages/locales/en-US/middle.ftl12
-rw-r--r--compiler/rustc_error_messages/locales/en-US/parser.ftl217
-rw-r--r--compiler/rustc_error_messages/locales/en-US/passes.ftl563
-rw-r--r--compiler/rustc_error_messages/locales/en-US/privacy.ftl2
-rw-r--r--compiler/rustc_error_messages/locales/en-US/query_system.ftl5
-rw-r--r--compiler/rustc_error_messages/locales/en-US/session.ftl20
-rw-r--r--compiler/rustc_error_messages/src/lib.rs77
-rw-r--r--compiler/rustc_errors/Cargo.toml3
-rw-r--r--compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs4
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs262
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs99
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs222
-rw-r--r--compiler/rustc_errors/src/emitter.rs4
-rw-r--r--compiler/rustc_errors/src/json.rs4
-rw-r--r--compiler/rustc_errors/src/lib.rs81
-rw-r--r--compiler/rustc_errors/src/translation.rs34
-rw-r--r--compiler/rustc_expand/src/base.rs59
-rw-r--r--compiler/rustc_expand/src/build.rs4
-rw-r--r--compiler/rustc_expand/src/config.rs10
-rw-r--r--compiler/rustc_expand/src/errors.rs26
-rw-r--r--compiler/rustc_expand/src/expand.rs72
-rw-r--r--compiler/rustc_expand/src/lib.rs1
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs26
-rw-r--r--compiler/rustc_expand/src/placeholders.rs8
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs146
-rw-r--r--compiler/rustc_expand/src/tokenstream/tests.rs18
-rw-r--r--compiler/rustc_feature/Cargo.toml1
-rw-r--r--compiler/rustc_feature/src/accepted.rs6
-rw-r--r--compiler/rustc_feature/src/active.rs10
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs43
-rw-r--r--compiler/rustc_hir/Cargo.toml1
-rw-r--r--compiler/rustc_hir/src/def.rs125
-rw-r--r--compiler/rustc_hir/src/hir.rs97
-rw-r--r--compiler/rustc_hir/src/hir_id.rs60
-rw-r--r--compiler/rustc_hir/src/intravisit.rs20
-rw-r--r--compiler/rustc_hir/src/lib.rs3
-rw-r--r--compiler/rustc_hir/src/stable_hash_impls.rs10
-rw-r--r--compiler/rustc_hir_analysis/Cargo.toml (renamed from compiler/rustc_typeck/Cargo.toml)3
-rw-r--r--compiler/rustc_hir_analysis/README.md (renamed from compiler/rustc_typeck/README.md)0
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs (renamed from compiler/rustc_typeck/src/astconv/errors.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/generics.rs (renamed from compiler/rustc_typeck/src/astconv/generics.rs)15
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs (renamed from compiler/rustc_typeck/src/astconv/mod.rs)214
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs (renamed from compiler/rustc_typeck/src/bounds.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs (renamed from compiler/rustc_typeck/src/check/check.rs)588
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_method.rs (renamed from compiler/rustc_typeck/src/check/compare_method.rs)1099
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs (renamed from compiler/rustc_typeck/src/check/dropck.rs)12
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs (renamed from compiler/rustc_typeck/src/check/intrinsic.rs)32
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs (renamed from compiler/rustc_typeck/src/check/intrinsicck.rs)112
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs (renamed from compiler/rustc_typeck/src/check/mod.rs)504
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs (renamed from compiler/rustc_typeck/src/check/region.rs)8
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs (renamed from compiler/rustc_typeck/src/check/wfcheck.rs)195
-rw-r--r--compiler/rustc_hir_analysis/src/check_unused.rs (renamed from compiler/rustc_typeck/src/check_unused.rs)31
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs572
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs (renamed from compiler/rustc_typeck/src/coherence/inherent_impls.rs)18
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs (renamed from compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs)58
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs (renamed from compiler/rustc_typeck/src/coherence/mod.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs (renamed from compiler/rustc_typeck/src/coherence/orphan.rs)38
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/unsafety.rs (renamed from compiler/rustc_typeck/src/coherence/unsafety.rs)32
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs (renamed from compiler/rustc_typeck/src/collect.rs)1302
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs481
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs (renamed from compiler/rustc_typeck/src/collect/item_bounds.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/collect/lifetimes.rs (renamed from compiler/rustc_resolve/src/late/lifetimes.rs)139
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs707
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs (renamed from compiler/rustc_typeck/src/collect/type_of.rs)128
-rw-r--r--compiler/rustc_hir_analysis/src/constrained_generic_params.rs (renamed from compiler/rustc_typeck/src/constrained_generic_params.rs)10
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs (renamed from compiler/rustc_typeck/src/errors.rs)233
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs (renamed from compiler/rustc_typeck/src/hir_wf_check.rs)58
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check.rs (renamed from compiler/rustc_typeck/src/impl_wf_check.rs)43
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs (renamed from compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs)98
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs (renamed from compiler/rustc_typeck/src/lib.rs)81
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/explicit.rs (renamed from compiler/rustc_typeck/src/outlives/explicit.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs (renamed from compiler/rustc_typeck/src/outlives/implicit_infer.rs)4
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/mod.rs (renamed from compiler/rustc_typeck/src/outlives/mod.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/test.rs (renamed from compiler/rustc_typeck/src/outlives/test.rs)6
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/utils.rs (renamed from compiler/rustc_typeck/src/outlives/utils.rs)17
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors.rs (renamed from compiler/rustc_typeck/src/structured_errors.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs (renamed from compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs (renamed from compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs (renamed from compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs (renamed from compiler/rustc_typeck/src/variance/constraints.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs (renamed from compiler/rustc_typeck/src/variance/mod.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/variance/solve.rs (renamed from compiler/rustc_typeck/src/variance/solve.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/variance/terms.rs (renamed from compiler/rustc_typeck/src/variance/terms.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/variance/test.rs (renamed from compiler/rustc_typeck/src/variance/test.rs)7
-rw-r--r--compiler/rustc_hir_analysis/src/variance/xform.rs (renamed from compiler/rustc_typeck/src/variance/xform.rs)0
-rw-r--r--compiler/rustc_hir_pretty/Cargo.toml1
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs8
-rw-r--r--compiler/rustc_hir_typeck/Cargo.toml28
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs (renamed from compiler/rustc_typeck/src/check/_match.rs)19
-rw-r--r--compiler/rustc_hir_typeck/src/autoderef.rs (renamed from compiler/rustc_typeck/src/check/autoderef.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs (renamed from compiler/rustc_typeck/src/check/callee.rs)401
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs (renamed from compiler/rustc_typeck/src/check/cast.rs)174
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs324
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs (renamed from compiler/rustc_typeck/src/check/closure.rs)37
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs (renamed from compiler/rustc_typeck/src/check/coercion.rs)83
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs (renamed from compiler/rustc_typeck/src/check/demand.rs)135
-rw-r--r--compiler/rustc_hir_typeck/src/diverges.rs (renamed from compiler/rustc_typeck/src/check/diverges.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs126
-rw-r--r--compiler/rustc_hir_typeck/src/expectation.rs (renamed from compiler/rustc_typeck/src/check/expectation.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs (renamed from compiler/rustc_typeck/src/check/expr.rs)118
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs (renamed from compiler/rustc_typeck/src/expr_use_visitor.rs)15
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs (renamed from compiler/rustc_typeck/src/check/fallback.rs)4
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs (renamed from compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs)116
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs (renamed from compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs (renamed from compiler/rustc_typeck/src/check/fn_ctxt/checks.rs)72
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs (renamed from compiler/rustc_typeck/src/check/fn_ctxt/mod.rs)26
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs (renamed from compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs)199
-rw-r--r--compiler/rustc_hir_typeck/src/gather_locals.rs (renamed from compiler/rustc_typeck/src/check/gather_locals.rs)3
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs (renamed from compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs)2
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs (renamed from compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs (renamed from compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs (renamed from compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs)2
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs (renamed from compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs)15
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs (renamed from compiler/rustc_typeck/src/check/generator_interior.rs)49
-rw-r--r--compiler/rustc_hir_typeck/src/inherited.rs (renamed from compiler/rustc_typeck/src/check/inherited.rs)38
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs108
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs507
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs (renamed from compiler/rustc_typeck/src/mem_categorization.rs)24
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs (renamed from compiler/rustc_typeck/src/check/method/confirm.rs)6
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs (renamed from compiler/rustc_typeck/src/check/method/mod.rs)5
-rw-r--r--compiler/rustc_hir_typeck/src/method/prelude2021.rs (renamed from compiler/rustc_typeck/src/check/method/prelude2021.rs)121
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs (renamed from compiler/rustc_typeck/src/check/method/probe.rs)163
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs (renamed from compiler/rustc_typeck/src/check/method/suggest.rs)388
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs (renamed from compiler/rustc_typeck/src/check/op.rs)15
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs (renamed from compiler/rustc_typeck/src/check/pat.rs)10
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs (renamed from compiler/rustc_typeck/src/check/place_op.rs)4
-rw-r--r--compiler/rustc_hir_typeck/src/rvalue_scopes.rs (renamed from compiler/rustc_typeck/src/check/rvalue_scopes.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs (renamed from compiler/rustc_typeck/src/check/upvar.rs)28
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs (renamed from compiler/rustc_typeck/src/check/writeback.rs)79
-rw-r--r--compiler/rustc_incremental/Cargo.toml1
-rw-r--r--compiler/rustc_incremental/src/lib.rs1
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs10
-rw-r--r--compiler/rustc_index/Cargo.toml1
-rw-r--r--compiler/rustc_index/src/lib.rs2
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs178
-rw-r--r--compiler/rustc_infer/src/errors/note_and_explain.rs15
-rw-r--r--compiler/rustc_infer/src/infer/at.rs7
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs6
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs20
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs57
-rw-r--r--compiler/rustc_infer/src/infer/equate.rs19
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs304
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs88
-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/mismatched_static_lifetime.rs18
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs18
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs31
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs7
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs31
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs4
-rw-r--r--compiler/rustc_infer/src/infer/fudge.rs4
-rw-r--r--compiler/rustc_infer/src/infer/glb.rs2
-rw-r--r--compiler/rustc_infer/src/infer/higher_ranked/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/lattice.rs2
-rw-r--r--compiler/rustc_infer/src/infer/lub.rs2
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs300
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs27
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs53
-rw-r--r--compiler/rustc_infer/src/infer/outlives/components.rs17
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs12
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs150
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs111
-rw-r--r--compiler/rustc_infer/src/infer/projection.rs2
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/leak_check.rs2
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs10
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs25
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs61
-rw-r--r--compiler/rustc_infer/src/lib.rs5
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs15
-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/structural_impls.rs1
-rw-r--r--compiler/rustc_infer/src/traits/util.rs12
-rw-r--r--compiler/rustc_interface/Cargo.toml4
-rw-r--r--compiler/rustc_interface/src/errors.rs58
-rw-r--r--compiler/rustc_interface/src/interface.rs109
-rw-r--r--compiler/rustc_interface/src/lib.rs1
-rw-r--r--compiler/rustc_interface/src/passes.rs23
-rw-r--r--compiler/rustc_interface/src/proc_macro_decls.rs5
-rw-r--r--compiler/rustc_interface/src/queries.rs4
-rw-r--r--compiler/rustc_interface/src/tests.rs43
-rw-r--r--compiler/rustc_interface/src/util.rs122
-rw-r--r--compiler/rustc_lexer/Cargo.toml1
-rw-r--r--compiler/rustc_lexer/src/cursor.rs16
-rw-r--r--compiler/rustc_lexer/src/lib.rs76
-rw-r--r--compiler/rustc_lexer/src/unescape.rs27
-rw-r--r--compiler/rustc_lint/Cargo.toml2
-rw-r--r--compiler/rustc_lint/src/array_into_iter.rs62
-rw-r--r--compiler/rustc_lint/src/builtin.rs896
-rw-r--r--compiler/rustc_lint/src/context.rs91
-rw-r--r--compiler/rustc_lint/src/early.rs8
-rw-r--r--compiler/rustc_lint/src/enum_intrinsics_non_enums.rs26
-rw-r--r--compiler/rustc_lint/src/errors.rs90
-rw-r--r--compiler/rustc_lint/src/expect.rs14
-rw-r--r--compiler/rustc_lint/src/for_loops_over_fallibles.rs183
-rw-r--r--compiler/rustc_lint/src/hidden_unicode_codepoints.rs94
-rw-r--r--compiler/rustc_lint/src/internal.rs215
-rw-r--r--compiler/rustc_lint/src/late.rs25
-rw-r--r--compiler/rustc_lint/src/let_underscore.rs67
-rw-r--r--compiler/rustc_lint/src/levels.rs957
-rw-r--r--compiler/rustc_lint/src/lib.rs15
-rw-r--r--compiler/rustc_lint/src/methods.rs19
-rw-r--r--compiler/rustc_lint/src/non_ascii_idents.rs68
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs113
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs111
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs27
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs163
-rw-r--r--compiler/rustc_lint/src/pass_by_value.rs18
-rw-r--r--compiler/rustc_lint/src/redundant_semicolon.rs19
-rw-r--r--compiler/rustc_lint/src/traits.rs36
-rw-r--r--compiler/rustc_lint/src/types.rs389
-rw-r--r--compiler/rustc_lint/src/unused.rs169
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs37
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs34
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp260
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp47
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs197
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs743
-rw-r--r--compiler/rustc_macros/src/diagnostics/fluent.rs65
-rw-r--r--compiler/rustc_macros/src/diagnostics/mod.rs36
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs492
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs421
-rw-r--r--compiler/rustc_macros/src/lib.rs5
-rw-r--r--compiler/rustc_macros/src/query.rs52
-rw-r--r--compiler/rustc_metadata/Cargo.toml1
-rw-r--r--compiler/rustc_metadata/src/errors.rs384
-rw-r--r--compiler/rustc_metadata/src/foreign_modules.rs6
-rw-r--r--compiler/rustc_metadata/src/lib.rs2
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs41
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs79
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs27
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs518
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs10
-rw-r--r--compiler/rustc_middle/Cargo.toml2
-rw-r--r--compiler/rustc_middle/benches/lib.rs54
-rw-r--r--compiler/rustc_middle/src/arena.rs5
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs152
-rw-r--r--compiler/rustc_middle/src/dep_graph/mod.rs52
-rw-r--r--compiler/rustc_middle/src/error.rs27
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs129
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs36
-rw-r--r--compiler/rustc_middle/src/infer/unify_key.rs2
-rw-r--r--compiler/rustc_middle/src/lib.rs6
-rw-r--r--compiler/rustc_middle/src/lint.rs329
-rw-r--r--compiler/rustc_middle/src/macros.rs13
-rw-r--r--compiler/rustc_middle/src/middle/limits.rs2
-rw-r--r--compiler/rustc_middle/src/middle/privacy.rs214
-rw-r--r--compiler/rustc_middle/src/middle/resolve_lifetime.rs15
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs11
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs19
-rw-r--r--compiler/rustc_middle/src/mir/interpret/pointer.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs42
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs114
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs6
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs3
-rw-r--r--compiler/rustc_middle/src/mir/query.rs9
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs26
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs5
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs28
-rw-r--r--compiler/rustc_middle/src/mir/type_visitable.rs19
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs7
-rw-r--r--compiler/rustc_middle/src/query/mod.rs302
-rw-r--r--compiler/rustc_middle/src/thir.rs9
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs16
-rw-r--r--compiler/rustc_middle/src/traits/query.rs4
-rw-r--r--compiler/rustc_middle/src/traits/select.rs12
-rw-r--r--compiler/rustc_middle/src/traits/structural_impls.rs2
-rw-r--r--compiler/rustc_middle/src/ty/abstract_const.rs12
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs3
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs27
-rw-r--r--compiler/rustc_middle/src/ty/cast.rs28
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs1
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs52
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs52
-rw-r--r--compiler/rustc_middle/src/ty/context.rs176
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs8
-rw-r--r--compiler/rustc_middle/src/ty/erase_regions.rs5
-rw-r--r--compiler/rustc_middle/src/ty/error.rs8
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs11
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs18
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs40
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs3
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs145
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs204
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/mod.rs258
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs6
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs2375
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs141
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs24
-rw-r--r--compiler/rustc_middle/src/ty/opaque_types.rs218
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs7
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs13
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs230
-rw-r--r--compiler/rustc_middle/src/ty/query.rs24
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs14
-rw-r--r--compiler/rustc_middle/src/ty/rvalue_scopes.rs2
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs55
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs150
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs134
-rw-r--r--compiler/rustc_middle/src/ty/util.rs41
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs32
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs16
-rw-r--r--compiler/rustc_middle/src/values.rs180
-rw-r--r--compiler/rustc_mir_build/Cargo.toml1
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs37
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_operand.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs76
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs24
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_temp.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs96
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs35
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs25
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs51
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs132
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs4
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs30
-rw-r--r--compiler/rustc_mir_build/src/lib.rs2
-rw-r--r--compiler/rustc_mir_build/src/lints.rs24
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs7
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs117
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs57
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs20
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs8
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs19
-rw-r--r--compiler/rustc_mir_dataflow/Cargo.toml1
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs5
-rw-r--r--compiler/rustc_mir_dataflow/src/errors.rs42
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs1
-rw-r--r--compiler/rustc_mir_transform/Cargo.toml1
-rw-r--r--compiler/rustc_mir_transform/src/check_const_item_mutation.rs18
-rw-r--r--compiler/rustc_mir_transform/src/check_packed_ref.rs40
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs24
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs6
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs47
-rw-r--r--compiler/rustc_mir_transform/src/coverage/test_macros/Cargo.toml1
-rw-r--r--compiler/rustc_mir_transform/src/deduce_param_attrs.rs248
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_box_derefs.rs1
-rw-r--r--compiler/rustc_mir_transform/src/ffi_unwind_calls.rs14
-rw-r--r--compiler/rustc_mir_transform/src/function_item_references.rs22
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs3
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs47
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs24
-rw-r--r--compiler/rustc_mir_transform/src/marker.rs20
-rw-r--r--compiler/rustc_mir_transform/src/pass_manager.rs89
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs8
-rw-r--r--compiler/rustc_monomorphize/Cargo.toml1
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs34
-rw-r--r--compiler/rustc_monomorphize/src/errors.rs37
-rw-r--r--compiler/rustc_monomorphize/src/lib.rs1
-rw-r--r--compiler/rustc_monomorphize/src/partitioning/default.rs6
-rw-r--r--compiler/rustc_monomorphize/src/polymorphize.rs53
-rw-r--r--compiler/rustc_parse/Cargo.toml1
-rw-r--r--compiler/rustc_parse/src/errors.rs1237
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs397
-rw-r--r--compiler/rustc_parse/src/lexer/tokentrees.rs428
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs19
-rw-r--r--compiler/rustc_parse/src/lib.rs6
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs159
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs33
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs946
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs509
-rw-r--r--compiler/rustc_parse/src/parser/generics.rs36
-rw-r--r--compiler/rustc_parse/src/parser/item.rs163
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs151
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs26
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs169
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs11
-rw-r--r--compiler/rustc_parse_format/src/lib.rs30
-rw-r--r--compiler/rustc_parse_format/src/tests.rs15
-rw-r--r--compiler/rustc_passes/src/check_attr.rs277
-rw-r--r--compiler/rustc_passes/src/check_const.rs17
-rw-r--r--compiler/rustc_passes/src/dead.rs136
-rw-r--r--compiler/rustc_passes/src/debugger_visualizer.rs15
-rw-r--r--compiler/rustc_passes/src/diagnostic_items.rs45
-rw-r--r--compiler/rustc_passes/src/entry.rs157
-rw-r--r--compiler/rustc_passes/src/errors.rs1095
-rw-r--r--compiler/rustc_passes/src/hir_id_validator.rs23
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs4
-rw-r--r--compiler/rustc_passes/src/lang_items.rs211
-rw-r--r--compiler/rustc_passes/src/layout_test.rs77
-rw-r--r--compiler/rustc_passes/src/lib.rs3
-rw-r--r--compiler/rustc_passes/src/lib_features.rs34
-rw-r--r--compiler/rustc_passes/src/liveness.rs65
-rw-r--r--compiler/rustc_passes/src/loops.rs161
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs88
-rw-r--r--compiler/rustc_passes/src/reachable.rs53
-rw-r--r--compiler/rustc_passes/src/stability.rs230
-rw-r--r--compiler/rustc_passes/src/weak_lang_items.rs31
-rw-r--r--compiler/rustc_plugin_impl/Cargo.toml1
-rw-r--r--compiler/rustc_plugin_impl/src/errors.rs10
-rw-r--r--compiler/rustc_privacy/Cargo.toml2
-rw-r--r--compiler/rustc_privacy/src/errors.rs42
-rw-r--r--compiler/rustc_privacy/src/lib.rs342
-rw-r--r--compiler/rustc_query_impl/src/keys.rs42
-rw-r--r--compiler/rustc_query_impl/src/lib.rs13
-rw-r--r--compiler/rustc_query_impl/src/on_disk_cache.rs13
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs188
-rw-r--r--compiler/rustc_query_impl/src/profiling_support.rs25
-rw-r--r--compiler/rustc_query_system/Cargo.toml1
-rw-r--r--compiler/rustc_query_system/src/dep_graph/dep_node.rs73
-rw-r--r--compiler/rustc_query_system/src/dep_graph/mod.rs45
-rw-r--r--compiler/rustc_query_system/src/error.rs73
-rw-r--r--compiler/rustc_query_system/src/ich/hcx.rs11
-rw-r--r--compiler/rustc_query_system/src/lib.rs5
-rw-r--r--compiler/rustc_query_system/src/query/config.rs2
-rw-r--r--compiler/rustc_query_system/src/query/job.rs33
-rw-r--r--compiler/rustc_query_system/src/query/mod.rs15
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs11
-rw-r--r--compiler/rustc_query_system/src/values.rs5
-rw-r--r--compiler/rustc_resolve/Cargo.toml1
-rw-r--r--compiler/rustc_resolve/src/access_levels.rs185
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs7
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs2
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs27
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs139
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs188
-rw-r--r--compiler/rustc_resolve/src/ident.rs22
-rw-r--r--compiler/rustc_resolve/src/imports.rs32
-rw-r--r--compiler/rustc_resolve/src/late.rs366
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs859
-rw-r--r--compiler/rustc_resolve/src/lib.rs82
-rw-r--r--compiler/rustc_resolve/src/macros.rs25
-rw-r--r--compiler/rustc_save_analysis/src/dump_visitor.rs83
-rw-r--r--compiler/rustc_save_analysis/src/errors.rs6
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs32
-rw-r--r--compiler/rustc_save_analysis/src/sig.rs12
-rw-r--r--compiler/rustc_serialize/src/lib.rs1
-rw-r--r--compiler/rustc_serialize/src/opaque.rs4
-rw-r--r--compiler/rustc_session/src/config.rs6
-rw-r--r--compiler/rustc_session/src/config/sigpipe.rs13
-rw-r--r--compiler/rustc_session/src/errors.rs198
-rw-r--r--compiler/rustc_session/src/lib.rs1
-rw-r--r--compiler/rustc_session/src/options.rs123
-rw-r--r--compiler/rustc_session/src/parse.rs46
-rw-r--r--compiler/rustc_session/src/session.rs191
-rw-r--r--compiler/rustc_session/src/utils.rs11
-rw-r--r--compiler/rustc_span/Cargo.toml1
-rw-r--r--compiler/rustc_span/src/def_id.rs20
-rw-r--r--compiler/rustc_span/src/lib.rs14
-rw-r--r--compiler/rustc_span/src/source_map.rs44
-rw-r--r--compiler/rustc_span/src/source_map/tests.rs45
-rw-r--r--compiler/rustc_span/src/span_encoding.rs42
-rw-r--r--compiler/rustc_span/src/symbol.rs35
-rw-r--r--compiler/rustc_symbol_mangling/Cargo.toml1
-rw-r--r--compiler/rustc_symbol_mangling/src/errors.rs6
-rw-r--r--compiler/rustc_symbol_mangling/src/test.rs8
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs4
-rw-r--r--compiler/rustc_target/Cargo.toml3
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs5
-rw-r--r--compiler/rustc_target/src/abi/mod.rs70
-rw-r--r--compiler/rustc_target/src/lib.rs1
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/aarch64_nintendo_switch_freestanding.rs4
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_none.rs4
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs4
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs4
-rw-r--r--compiler/rustc_target/src/spec/abi.rs138
-rw-r--r--compiler/rustc_target/src/spec/android_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs22
-rw-r--r--compiler/rustc_target/src/spec/armebv7r_none_eabi.rs5
-rw-r--r--compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs5
-rw-r--r--compiler/rustc_target/src/spec/armv4t_none_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/armv5te_none_eabi.rs41
-rw-r--r--compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs5
-rw-r--r--compiler/rustc_target/src/spec/armv7_linux_androideabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/armv7a_none_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/armv7a_none_eabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/armv7r_none_eabi.rs5
-rw-r--r--compiler/rustc_target/src/spec/armv7r_none_eabihf.rs5
-rw-r--r--compiler/rustc_target/src/spec/avr_gnu_base.rs9
-rw-r--r--compiler/rustc_target/src/spec/fuchsia_base.rs6
-rw-r--r--compiler/rustc_target/src/spec/hermit_base.rs6
-rw-r--r--compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs4
-rw-r--r--compiler/rustc_target/src/spec/i386_apple_ios.rs3
-rw-r--r--compiler/rustc_target/src/spec/i686_apple_darwin.rs7
-rw-r--r--compiler/rustc_target/src/spec/i686_linux_android.rs3
-rw-r--r--compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs9
-rw-r--r--compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs4
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_freebsd.rs7
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_haiku.rs7
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs7
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_netbsd.rs7
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_openbsd.rs7
-rw-r--r--compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs9
-rw-r--r--compiler/rustc_target/src/spec/i686_wrs_vxworks.rs7
-rw-r--r--compiler/rustc_target/src/spec/illumos_base.rs6
-rw-r--r--compiler/rustc_target/src/spec/l4re_base.rs5
-rw-r--r--compiler/rustc_target/src/spec/linux_kernel_base.rs3
-rw-r--r--compiler/rustc_target/src/spec/mipsel_sony_psp.rs10
-rw-r--r--compiler/rustc_target/src/spec/mipsel_unknown_none.rs5
-rw-r--r--compiler/rustc_target/src/spec/mod.rs244
-rw-r--r--compiler/rustc_target/src/spec/msp430_none_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/msvc_base.rs8
-rw-r--r--compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs1
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs5
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs9
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs5
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs5
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs5
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs5
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs5
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs5
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs5
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs5
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs5
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs5
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs3
-rw-r--r--compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs5
-rw-r--r--compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs5
-rw-r--r--compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs5
-rw-r--r--compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs5
-rw-r--r--compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs5
-rw-r--r--compiler/rustc_target/src/spec/riscv32imac_unknown_xous_elf.rs5
-rw-r--r--compiler/rustc_target/src/spec/riscv32imc_esp_espidf.rs4
-rw-r--r--compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs5
-rw-r--r--compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs6
-rw-r--r--compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs11
-rw-r--r--compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs11
-rw-r--r--compiler/rustc_target/src/spec/solaris_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs4
-rw-r--r--compiler/rustc_target/src/spec/tests/tests_impl.rs85
-rw-r--r--compiler/rustc_target/src/spec/thumb_base.rs5
-rw-r--r--compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs7
-rw-r--r--compiler/rustc_target/src/spec/thumbv5te_none_eabi.rs41
-rw-r--r--compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs4
-rw-r--r--compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/uefi_msvc_base.rs7
-rw-r--r--compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs8
-rw-r--r--compiler/rustc_target/src/spec/wasm32_wasi.rs6
-rw-r--r--compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs8
-rw-r--r--compiler/rustc_target/src/spec/wasm_base.rs9
-rw-r--r--compiler/rustc_target/src/spec/windows_gnu_base.rs28
-rw-r--r--compiler/rustc_target/src/spec/windows_gnullvm_base.rs10
-rw-r--r--compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs7
-rw-r--r--compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_darwin.rs9
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_ios.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs7
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_tvos.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs8
-rw-r--r--compiler/rustc_target/src/spec/x86_64_fuchsia.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_linux_android.rs7
-rw-r--r--compiler/rustc_target/src/spec/x86_64_pc_solaris.rs7
-rw-r--r--compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs9
-rw-r--r--compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs4
-rw-r--r--compiler/rustc_target/src/spec/x86_64_sun_solaris.rs7
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs7
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs7
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs7
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs3
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs4
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs7
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs7
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs7
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs7
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_none.rs7
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs4
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs7
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_redox.rs7
-rw-r--r--compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs9
-rw-r--r--compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs7
-rw-r--r--compiler/rustc_trait_selection/Cargo.toml1
-rw-r--r--compiler/rustc_trait_selection/src/autoderef.rs4
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs46
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs26
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs234
-rw-r--r--compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs89
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs102
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs63
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs721
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs370
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs84
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs111
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs175
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs176
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs142
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs54
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/relationships.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs29
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs72
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs149
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs83
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs48
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs46
-rw-r--r--compiler/rustc_traits/src/chalk/db.rs2
-rw-r--r--compiler/rustc_traits/src/dropck_outlives.rs220
-rw-r--r--compiler/rustc_traits/src/evaluate_obligation.rs20
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs7
-rw-r--r--compiler/rustc_traits/src/lib.rs1
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs46
-rw-r--r--compiler/rustc_traits/src/type_op.rs10
-rw-r--r--compiler/rustc_transmute/src/layout/tree.rs22
-rw-r--r--compiler/rustc_transmute/src/lib.rs19
-rw-r--r--compiler/rustc_ty_utils/Cargo.toml2
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs551
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs18
-rw-r--r--compiler/rustc_ty_utils/src/common_traits.rs11
-rw-r--r--compiler/rustc_ty_utils/src/consts.rs15
-rw-r--r--compiler/rustc_ty_utils/src/errors.rs56
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs75
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs1803
-rw-r--r--compiler/rustc_ty_utils/src/layout_sanity_check.rs (renamed from compiler/rustc_middle/src/ty/layout_sanity_check.rs)2
-rw-r--r--compiler/rustc_ty_utils/src/lib.rs10
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs5
-rw-r--r--compiler/rustc_ty_utils/src/representability.rs451
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs20
-rw-r--r--compiler/rustc_type_ir/Cargo.toml1
-rw-r--r--compiler/rustc_type_ir/src/lib.rs6
-rw-r--r--compiler/rustc_type_ir/src/sty.rs4
-rw-r--r--compiler/rustc_typeck/src/coherence/builtin.rs594
876 files changed, 34334 insertions, 27141 deletions
diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs
index 0de1a7819..e21c9b660 100644
--- a/compiler/rustc/src/main.rs
+++ b/compiler/rustc/src/main.rs
@@ -1,3 +1,5 @@
+#![feature(unix_sigpipe)]
+
// A note about jemalloc: rustc uses jemalloc when built for CI and
// distribution. The obvious way to do this is with the `#[global_allocator]`
// mechanism. However, for complicated reasons (see
@@ -23,6 +25,7 @@
// libraries. So we must reference jemalloc symbols one way or another, because
// this file is the only object code in the rustc executable.
+#[unix_sigpipe = "sig_dfl"]
fn main() {
// See the comment at the top of this file for an explanation of this.
#[cfg(feature = "jemalloc-sys")]
@@ -58,6 +61,5 @@ fn main() {
}
}
- rustc_driver::set_sigpipe_handler();
rustc_driver::main()
}
diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml
index c24180bac..fcbf96818 100644
--- a/compiler/rustc_ast/Cargo.toml
+++ b/compiler/rustc_ast/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
bitflags = "1.2.1"
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index d86db8f8b..4ef43735a 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1112,24 +1112,6 @@ pub struct Expr {
}
impl Expr {
- /// Returns `true` if this expression would be valid somewhere that expects a value;
- /// for example, an `if` condition.
- pub fn returns(&self) -> bool {
- if let ExprKind::Block(ref block, _) = self.kind {
- match block.stmts.last().map(|last_stmt| &last_stmt.kind) {
- // Implicit return
- Some(StmtKind::Expr(_)) => true,
- // Last statement is an explicit return?
- Some(StmtKind::Semi(expr)) => matches!(expr.kind, ExprKind::Ret(_)),
- // This is a block that doesn't end in either an implicit or explicit return.
- _ => false,
- }
- } else {
- // This is not a block, it is a value.
- true
- }
- }
-
/// Is this expr either `N`, or `{ N }`.
///
/// If this is not the case, name resolution does not resolve `N` when using
@@ -1338,14 +1320,13 @@ pub enum ExprKind {
///
/// The `PathSegment` represents the method name and its generic arguments
/// (within the angle brackets).
- /// The first element of the vector of an `Expr` is the expression that evaluates
- /// to the object on which the method is being called on (the receiver),
- /// and the remaining elements are the rest of the arguments.
- /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
- /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
+ /// The standalone `Expr` is the receiver expression.
+ /// The vector of `Expr` is the arguments.
+ /// `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
+ /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, x, [a, b, c, d])`.
/// This `Span` is the span of the function, without the dot and receiver
/// (e.g. `foo(a, b)` in `x.foo(a, b)`
- MethodCall(PathSegment, Vec<P<Expr>>, Span),
+ MethodCall(PathSegment, P<Expr>, Vec<P<Expr>>, Span),
/// A tuple (e.g., `(a, b, c, d)`).
Tup(Vec<P<Expr>>),
/// A binary operation (e.g., `a + b`, `a * b`).
@@ -2957,7 +2938,7 @@ pub enum AssocItemKind {
/// An associated function.
Fn(Box<Fn>),
/// An associated type.
- TyAlias(Box<TyAlias>),
+ Type(Box<TyAlias>),
/// A macro expanding to associated items.
MacCall(P<MacCall>),
}
@@ -2967,7 +2948,7 @@ impl AssocItemKind {
match *self {
Self::Const(defaultness, ..)
| Self::Fn(box Fn { defaultness, .. })
- | Self::TyAlias(box TyAlias { defaultness, .. }) => defaultness,
+ | Self::Type(box TyAlias { defaultness, .. }) => defaultness,
Self::MacCall(..) => Defaultness::Final,
}
}
@@ -2978,7 +2959,7 @@ impl From<AssocItemKind> for ItemKind {
match assoc_item_kind {
AssocItemKind::Const(a, b, c) => ItemKind::Const(a, b, c),
AssocItemKind::Fn(fn_kind) => ItemKind::Fn(fn_kind),
- AssocItemKind::TyAlias(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
+ AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
AssocItemKind::MacCall(a) => ItemKind::MacCall(a),
}
}
@@ -2991,7 +2972,7 @@ impl TryFrom<ItemKind> for AssocItemKind {
Ok(match item_kind {
ItemKind::Const(a, b, c) => AssocItemKind::Const(a, b, c),
ItemKind::Fn(fn_kind) => AssocItemKind::Fn(fn_kind),
- ItemKind::TyAlias(ty_alias_kind) => AssocItemKind::TyAlias(ty_alias_kind),
+ ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind),
ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
_ => return Err(item_kind),
})
@@ -3043,14 +3024,13 @@ pub type ForeignItem = Item<ForeignItemKind>;
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;
- // These are in alphabetical order, which is easy to maintain.
+ // tidy-alphabetical-start
static_assert_size!(AssocItem, 104);
static_assert_size!(AssocItemKind, 32);
static_assert_size!(Attribute, 32);
static_assert_size!(Block, 48);
static_assert_size!(Expr, 104);
static_assert_size!(ExprKind, 72);
- #[cfg(not(bootstrap))]
static_assert_size!(Fn, 184);
static_assert_size!(ForeignItem, 96);
static_assert_size!(ForeignItemKind, 24);
@@ -3065,11 +3045,12 @@ mod size_asserts {
static_assert_size!(Local, 72);
static_assert_size!(Param, 40);
static_assert_size!(Pat, 120);
- static_assert_size!(PatKind, 96);
static_assert_size!(Path, 40);
static_assert_size!(PathSegment, 24);
+ static_assert_size!(PatKind, 96);
static_assert_size!(Stmt, 32);
static_assert_size!(StmtKind, 16);
static_assert_size!(Ty, 96);
static_assert_size!(TyKind, 72);
+ // tidy-alphabetical-end
}
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index bd7a85b07..eeb7e56e2 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -13,9 +13,7 @@
#![feature(const_default_impls)]
#![feature(const_trait_impl)]
#![feature(if_let_guard)]
-#![cfg_attr(bootstrap, feature(label_break_value))]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(min_specialization)]
#![feature(negative_impls)]
#![feature(slice_internals)]
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 9fd0b63c4..b970e57e0 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -152,6 +152,12 @@ pub trait MutVisitor: Sized {
noop_visit_expr(e, self);
}
+ /// This method is a hack to workaround unstable of `stmt_expr_attributes`.
+ /// It can be removed once that feature is stabilized.
+ fn visit_method_receiver_expr(&mut self, ex: &mut P<Expr>) {
+ self.visit_expr(ex)
+ }
+
fn filter_map_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> {
noop_filter_map_expr(e, self)
}
@@ -1106,7 +1112,7 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
visit_fn_sig(sig, visitor);
visit_opt(body, |body| visitor.visit_block(body));
}
- AssocItemKind::TyAlias(box TyAlias {
+ AssocItemKind::Type(box TyAlias {
defaultness,
generics,
where_clauses,
@@ -1297,10 +1303,11 @@ pub fn noop_visit_expr<T: MutVisitor>(
vis.visit_expr(f);
visit_exprs(args, vis);
}
- ExprKind::MethodCall(PathSegment { ident, id, args }, exprs, span) => {
+ ExprKind::MethodCall(PathSegment { ident, id, args }, receiver, exprs, span) => {
vis.visit_ident(ident);
vis.visit_id(id);
visit_opt(args, |args| vis.visit_generic_args(args));
+ vis.visit_method_receiver_expr(receiver);
visit_exprs(exprs, vis);
vis.visit_span(span);
}
@@ -1588,3 +1595,9 @@ impl DummyAstNode for Crate {
}
}
}
+
+impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNodeWrapper<N, T> {
+ fn dummy() -> Self {
+ crate::ast_traits::AstNodeWrapper::new(N::dummy(), T::dummy())
+ }
+}
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 97dfb7837..83b10d906 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -13,7 +13,7 @@ use rustc_span::symbol::{kw, sym};
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{self, edition::Edition, Span, DUMMY_SP};
use std::borrow::Cow;
-use std::{fmt, mem};
+use std::fmt;
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum CommentKind {
@@ -256,10 +256,6 @@ pub enum TokenKind {
Eof,
}
-// `TokenKind` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(TokenKind, 16);
-
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct Token {
pub kind: TokenKind,
@@ -335,11 +331,6 @@ impl Token {
Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span)
}
- /// Return this token by value and leave a dummy token in its place.
- pub fn take(&mut self) -> Self {
- mem::replace(self, Token::dummy())
- }
-
/// For interpolated tokens, returns a span of the fragment to which the interpolated
/// token refers. For all other tokens this is just a regular span.
/// It is particularly important to use this for identifiers and lifetimes
@@ -354,17 +345,14 @@ impl Token {
}
pub fn is_op(&self) -> bool {
- !matches!(
- self.kind,
- OpenDelim(..)
- | CloseDelim(..)
- | Literal(..)
- | DocComment(..)
- | Ident(..)
- | Lifetime(..)
- | Interpolated(..)
- | Eof
- )
+ match self.kind {
+ Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Not | Tilde | BinOp(_)
+ | BinOpEq(_) | At | Dot | DotDot | DotDotDot | DotDotEq | Comma | Semi | Colon
+ | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | SingleQuote => true,
+
+ OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
+ | Lifetime(..) | Interpolated(..) | Eof => false,
+ }
}
pub fn is_like_plus(&self) -> bool {
@@ -733,6 +721,7 @@ impl Token {
}
impl PartialEq<TokenKind> for Token {
+ #[inline]
fn eq(&self, rhs: &TokenKind) -> bool {
self.kind == *rhs
}
@@ -756,10 +745,6 @@ pub enum Nonterminal {
NtVis(P<ast::Visibility>),
}
-// `Nonterminal` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Nonterminal, 16);
-
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)]
pub enum NonterminalKind {
Item,
@@ -898,3 +883,17 @@ where
panic!("interpolated tokens should not be present in the HIR")
}
}
+
+// Some types are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+ use super::*;
+ use rustc_data_structures::static_assert_size;
+ // tidy-alphabetical-start
+ static_assert_size!(Lit, 12);
+ static_assert_size!(LitKind, 2);
+ static_assert_size!(Nonterminal, 16);
+ static_assert_size!(Token, 24);
+ static_assert_size!(TokenKind, 16);
+ // tidy-alphabetical-end
+}
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 875cd620d..015f5c1ee 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -47,10 +47,6 @@ pub enum TokenTree {
Delimited(DelimSpan, Delimiter, TokenStream),
}
-// This type is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(TokenTree, 32);
-
// Ensure all fields of `TokenTree` is `Send` and `Sync`.
#[cfg(parallel_compiler)]
fn _dummy()
@@ -249,12 +245,12 @@ impl AttrTokenStream {
// properly implemented - we always synthesize fake tokens,
// so we never reach this code.
- let mut builder = TokenStreamBuilder::new();
+ let mut stream = TokenStream::default();
for inner_attr in inner_attrs {
- builder.push(inner_attr.tokens());
+ stream.push_stream(inner_attr.tokens());
}
- builder.push(delim_tokens.clone());
- *tree = TokenTree::Delimited(*span, *delim, builder.build());
+ stream.push_stream(delim_tokens.clone());
+ *tree = TokenTree::Delimited(*span, *delim, stream);
found = true;
break;
}
@@ -308,13 +304,20 @@ pub struct AttributesData {
#[derive(Clone, Debug, Default, Encodable, Decodable)]
pub struct TokenStream(pub(crate) Lrc<Vec<TokenTree>>);
-// `TokenStream` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(TokenStream, 8);
-
+/// Similar to `proc_macro::Spacing`, but for tokens.
+///
+/// Note that all `ast::TokenTree::Token` instances have a `Spacing`, but when
+/// we convert to `proc_macro::TokenTree` for proc macros only `Punct`
+/// `TokenTree`s have a `proc_macro::Spacing`.
#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
pub enum Spacing {
+ /// The token is not immediately followed by an operator token (as
+ /// determined by `Token::is_op`). E.g. a `+` token is `Alone` in `+ =`,
+ /// `+/*foo*/=`, `+ident`, and `+()`.
Alone,
+
+ /// The token is immediately followed by an operator token. E.g. a `+`
+ /// token is `Joint` in `+=` and `++`.
Joint,
}
@@ -502,76 +505,49 @@ impl TokenStream {
self.trees().map(|tree| TokenStream::flatten_token_tree(tree)).collect()
}
-}
-// 99.5%+ of the time we have 1 or 2 elements in this vector.
-#[derive(Clone)]
-pub struct TokenStreamBuilder(SmallVec<[TokenStream; 2]>);
-
-impl TokenStreamBuilder {
- pub fn new() -> TokenStreamBuilder {
- TokenStreamBuilder(SmallVec::new())
- }
-
- pub fn push(&mut self, stream: TokenStream) {
- self.0.push(stream);
- }
-
- pub fn build(self) -> TokenStream {
- let mut streams = self.0;
- match streams.len() {
- 0 => TokenStream::default(),
- 1 => streams.pop().unwrap(),
- _ => {
- // We will extend the first stream in `streams` with the
- // elements from the subsequent streams. This requires using
- // `make_mut()` on the first stream, and in practice this
- // doesn't cause cloning 99.9% of the time.
- //
- // One very common use case is when `streams` has two elements,
- // where the first stream has any number of elements within
- // (often 1, but sometimes many more) and the second stream has
- // a single element within.
-
- // Determine how much the first stream will be extended.
- // Needed to avoid quadratic blow up from on-the-fly
- // reallocations (#57735).
- let num_appends = streams.iter().skip(1).map(|ts| ts.len()).sum();
-
- // Get the first stream, which will become the result stream.
- // If it's `None`, create an empty stream.
- let mut iter = streams.into_iter();
- let mut res_stream_lrc = iter.next().unwrap().0;
-
- // Append the subsequent elements to the result stream, after
- // reserving space for them.
- let res_vec_mut = Lrc::make_mut(&mut res_stream_lrc);
- res_vec_mut.reserve(num_appends);
- for stream in iter {
- let stream_iter = stream.0.iter().cloned();
-
- // If (a) `res_mut_vec` is not empty and the last tree
- // within it is a token tree marked with `Joint`, and (b)
- // `stream` is not empty and the first tree within it is a
- // token tree, and (c) the two tokens can be glued
- // together...
- if let Some(TokenTree::Token(last_tok, Spacing::Joint)) = res_vec_mut.last()
- && let Some(TokenTree::Token(tok, spacing)) = stream.0.first()
- && let Some(glued_tok) = last_tok.glue(&tok)
- {
- // ...then overwrite the last token tree in
- // `res_vec_mut` with the glued token, and skip the
- // first token tree from `stream`.
- *res_vec_mut.last_mut().unwrap() = TokenTree::Token(glued_tok, *spacing);
- res_vec_mut.extend(stream_iter.skip(1));
- } else {
- // Append all of `stream`.
- res_vec_mut.extend(stream_iter);
- }
- }
+ // If `vec` is not empty, try to glue `tt` onto its last token. The return
+ // value indicates if gluing took place.
+ fn try_glue_to_last(vec: &mut Vec<TokenTree>, tt: &TokenTree) -> bool {
+ if let Some(TokenTree::Token(last_tok, Spacing::Joint)) = vec.last()
+ && let TokenTree::Token(tok, spacing) = tt
+ && let Some(glued_tok) = last_tok.glue(&tok)
+ {
+ // ...then overwrite the last token tree in `vec` with the
+ // glued token, and skip the first token tree from `stream`.
+ *vec.last_mut().unwrap() = TokenTree::Token(glued_tok, *spacing);
+ true
+ } else {
+ false
+ }
+ }
- TokenStream(res_stream_lrc)
- }
+ // Push `tt` onto the end of the stream, possibly gluing it to the last
+ // token. Uses `make_mut` to maximize efficiency.
+ pub fn push_tree(&mut self, tt: TokenTree) {
+ let vec_mut = Lrc::make_mut(&mut self.0);
+
+ if Self::try_glue_to_last(vec_mut, &tt) {
+ // nothing else to do
+ } else {
+ vec_mut.push(tt);
+ }
+ }
+
+ // Push `stream` onto the end of the stream, possibly gluing the first
+ // token tree to the last token. (No other token trees will be glued.)
+ // Uses `make_mut` to maximize efficiency.
+ pub fn push_stream(&mut self, stream: TokenStream) {
+ let vec_mut = Lrc::make_mut(&mut self.0);
+
+ let stream_iter = stream.0.iter().cloned();
+
+ if let Some(first) = stream.0.first() && Self::try_glue_to_last(vec_mut, first) {
+ // Now skip the first token tree from `stream`.
+ vec_mut.extend(stream_iter.skip(1));
+ } else {
+ // Append all of `stream`.
+ vec_mut.extend(stream_iter);
}
}
}
@@ -664,3 +640,17 @@ impl DelimSpan {
self.open.with_hi(self.close.hi())
}
}
+
+// Some types are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+ use super::*;
+ use rustc_data_structures::static_assert_size;
+ // tidy-alphabetical-start
+ static_assert_size!(AttrTokenStream, 8);
+ static_assert_size!(AttrTokenTree, 32);
+ static_assert_size!(LazyAttrTokenStream, 8);
+ static_assert_size!(TokenStream, 8);
+ static_assert_size!(TokenTree, 32);
+ // tidy-alphabetical-end
+}
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index 6c5c7f66f..b40ad6f70 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -396,9 +396,9 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
contains_exterior_struct_lit(&x)
}
- ast::ExprKind::MethodCall(.., ref exprs, _) => {
+ ast::ExprKind::MethodCall(_, ref receiver, _, _) => {
// X { y: 1 }.bar(...)
- contains_exterior_struct_lit(&exprs[0])
+ contains_exterior_struct_lit(&receiver)
}
_ => false,
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 1d0de5a4b..6f56c1ef0 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -140,6 +140,11 @@ pub trait Visitor<'ast>: Sized {
fn visit_expr(&mut self, ex: &'ast Expr) {
walk_expr(self, ex)
}
+ /// This method is a hack to workaround unstable of `stmt_expr_attributes`.
+ /// It can be removed once that feature is stabilized.
+ fn visit_method_receiver_expr(&mut self, ex: &'ast Expr) {
+ self.visit_expr(ex)
+ }
fn visit_expr_post(&mut self, _ex: &'ast Expr) {}
fn visit_ty(&mut self, t: &'ast Ty) {
walk_ty(self, t)
@@ -244,14 +249,12 @@ pub trait Visitor<'ast>: Sized {
#[macro_export]
macro_rules! walk_list {
- ($visitor: expr, $method: ident, $list: expr) => {
- for elem in $list {
- $visitor.$method(elem)
- }
- };
- ($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => {
- for elem in $list {
- $visitor.$method(elem, $($extra_args,)*)
+ ($visitor: expr, $method: ident, $list: expr $(, $($extra_args: expr),* )?) => {
+ {
+ #[cfg_attr(not(bootstrap), allow(for_loops_over_fallibles))]
+ for elem in $list {
+ $visitor.$method(elem $(, $($extra_args,)* )?)
+ }
}
}
}
@@ -685,7 +688,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref());
visitor.visit_fn(kind, span, id);
}
- AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
+ AssocItemKind::Type(box TyAlias { generics, bounds, ty, .. }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
walk_list!(visitor, visit_ty, ty);
@@ -795,8 +798,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
visitor.visit_expr(callee_expression);
walk_list!(visitor, visit_expr, arguments);
}
- ExprKind::MethodCall(ref segment, ref arguments, _span) => {
+ ExprKind::MethodCall(ref segment, ref receiver, ref arguments, _span) => {
visitor.visit_path_segment(segment);
+ visitor.visit_expr(receiver);
walk_list!(visitor, visit_expr, arguments);
}
ExprKind::Binary(_, ref left_expression, ref right_expression) => {
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index 24672efc6..450cdf246 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -192,26 +192,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
InlineAsmOperand::Sym { ref sym } => {
- if !self.tcx.features().asm_sym {
- feature_err(
- &sess.parse_sess,
- sym::asm_sym,
- *op_sp,
- "sym operands for inline assembly are unstable",
- )
- .emit();
- }
-
let static_def_id = self
.resolver
.get_partial_res(sym.id)
- .filter(|res| res.unresolved_segments() == 0)
- .and_then(|res| {
- if let Res::Def(DefKind::Static(_), def_id) = res.base_res() {
- Some(def_id)
- } else {
- None
- }
+ .and_then(|res| res.full_res())
+ .and_then(|res| match res {
+ Res::Def(DefKind::Static(_), def_id) => Some(def_id),
+ _ => None,
});
if let Some(def_id) = static_def_id {
@@ -237,7 +224,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// Wrap the expression in an AnonConst.
let parent_def_id = self.current_hir_id_owner;
let node_id = self.next_node_id();
- self.create_def(parent_def_id, node_id, DefPathData::AnonConst);
+ self.create_def(parent_def_id.def_id, node_id, DefPathData::AnonConst);
let anon_const = AnonConst { id: node_id, value: P(expr) };
hir::InlineAsmOperand::SymFn {
anon_const: self.lower_anon_const(&anon_const),
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index c87d0ca96..157f46501 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -1,9 +1,9 @@
-use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic, DiagnosticArgFromDisplay};
-use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
+use rustc_errors::DiagnosticArgFromDisplay;
+use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{symbol::Ident, Span, Symbol};
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::generic_type_with_parentheses, code = "E0214")]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_generic_type_with_parentheses, code = "E0214")]
pub struct GenericTypeWithParentheses {
#[primary_span]
#[label]
@@ -12,35 +12,42 @@ pub struct GenericTypeWithParentheses {
pub sub: Option<UseAngleBrackets>,
}
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Subdiagnostic)]
+#[multipart_suggestion(ast_lowering_use_angle_brackets, applicability = "maybe-incorrect")]
pub struct UseAngleBrackets {
+ #[suggestion_part(code = "<")]
pub open_param: Span,
+ #[suggestion_part(code = ">")]
pub close_param: Span,
}
-impl AddSubdiagnostic for UseAngleBrackets {
- fn add_to_diagnostic(self, diag: &mut Diagnostic) {
- diag.multipart_suggestion(
- fluent::ast_lowering::use_angle_brackets,
- vec![(self.open_param, String::from("<")), (self.close_param, String::from(">"))],
- Applicability::MaybeIncorrect,
- );
- }
-}
-
-#[derive(SessionDiagnostic)]
-#[help]
-#[diag(ast_lowering::invalid_abi, code = "E0703")]
+#[derive(Diagnostic)]
+#[diag(ast_lowering_invalid_abi, code = "E0703")]
+#[note]
pub struct InvalidAbi {
#[primary_span]
#[label]
pub span: Span,
pub abi: Symbol,
- pub valid_abis: String,
+ pub command: String,
+ #[subdiagnostic]
+ pub suggestion: Option<InvalidAbiSuggestion>,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(
+ ast_lowering_invalid_abi_suggestion,
+ code = "{suggestion}",
+ applicability = "maybe-incorrect"
+)]
+pub struct InvalidAbiSuggestion {
+ #[primary_span]
+ pub span: Span,
+ pub suggestion: String,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::assoc_ty_parentheses)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_assoc_ty_parentheses)]
pub struct AssocTyParentheses {
#[primary_span]
pub span: Span,
@@ -48,123 +55,116 @@ pub struct AssocTyParentheses {
pub sub: AssocTyParenthesesSub,
}
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Subdiagnostic)]
pub enum AssocTyParenthesesSub {
- Empty { parentheses_span: Span },
- NotEmpty { open_param: Span, close_param: Span },
-}
-
-impl AddSubdiagnostic for AssocTyParenthesesSub {
- fn add_to_diagnostic(self, diag: &mut Diagnostic) {
- match self {
- Self::Empty { parentheses_span } => diag.multipart_suggestion(
- fluent::ast_lowering::remove_parentheses,
- vec![(parentheses_span, String::new())],
- Applicability::MaybeIncorrect,
- ),
- Self::NotEmpty { open_param, close_param } => diag.multipart_suggestion(
- fluent::ast_lowering::use_angle_brackets,
- vec![(open_param, String::from("<")), (close_param, String::from(">"))],
- Applicability::MaybeIncorrect,
- ),
- };
- }
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(ast_lowering::misplaced_impl_trait, code = "E0562")]
+ #[multipart_suggestion(ast_lowering_remove_parentheses)]
+ Empty {
+ #[suggestion_part(code = "")]
+ parentheses_span: Span,
+ },
+ #[multipart_suggestion(ast_lowering_use_angle_brackets)]
+ NotEmpty {
+ #[suggestion_part(code = "<")]
+ open_param: Span,
+ #[suggestion_part(code = ">")]
+ close_param: Span,
+ },
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_lowering_misplaced_impl_trait, code = "E0562")]
pub struct MisplacedImplTrait<'a> {
#[primary_span]
pub span: Span,
pub position: DiagnosticArgFromDisplay<'a>,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::rustc_box_attribute_error)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_rustc_box_attribute_error)]
pub struct RustcBoxAttributeError {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::underscore_expr_lhs_assign)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_underscore_expr_lhs_assign)]
pub struct UnderscoreExprLhsAssign {
#[primary_span]
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::base_expression_double_dot)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_base_expression_double_dot)]
pub struct BaseExpressionDoubleDot {
#[primary_span]
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::await_only_in_async_fn_and_blocks, code = "E0728")]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = "E0728")]
pub struct AwaitOnlyInAsyncFnAndBlocks {
#[primary_span]
#[label]
pub dot_await_span: Span,
- #[label(ast_lowering::this_not_async)]
+ #[label(ast_lowering_this_not_async)]
pub item_span: Option<Span>,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::generator_too_many_parameters, code = "E0628")]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_generator_too_many_parameters, code = "E0628")]
pub struct GeneratorTooManyParameters {
#[primary_span]
pub fn_decl_span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::closure_cannot_be_static, code = "E0697")]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_closure_cannot_be_static, code = "E0697")]
pub struct ClosureCannotBeStatic {
#[primary_span]
pub fn_decl_span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
+#[derive(Diagnostic, Clone, Copy)]
#[help]
-#[diag(ast_lowering::async_non_move_closure_not_supported, code = "E0708")]
+#[diag(ast_lowering_async_non_move_closure_not_supported, code = "E0708")]
pub struct AsyncNonMoveClosureNotSupported {
#[primary_span]
pub fn_decl_span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::functional_record_update_destructuring_assignment)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_functional_record_update_destructuring_assignment)]
pub struct FunctionalRecordUpdateDestructuringAssignemnt {
#[primary_span]
#[suggestion(code = "", applicability = "machine-applicable")]
pub span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::async_generators_not_supported, code = "E0727")]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_async_generators_not_supported, code = "E0727")]
pub struct AsyncGeneratorsNotSupported {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::inline_asm_unsupported_target, code = "E0472")]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_inline_asm_unsupported_target, code = "E0472")]
pub struct InlineAsmUnsupportedTarget {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::att_syntax_only_x86)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_att_syntax_only_x86)]
pub struct AttSyntaxOnlyX86 {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::abi_specified_multiple_times)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_abi_specified_multiple_times)]
pub struct AbiSpecifiedMultipleTimes {
#[primary_span]
pub abi_span: Span,
@@ -175,24 +175,24 @@ pub struct AbiSpecifiedMultipleTimes {
pub equivalent: Option<()>,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::clobber_abi_not_supported)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_clobber_abi_not_supported)]
pub struct ClobberAbiNotSupported {
#[primary_span]
pub abi_span: Span,
}
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
#[note]
-#[diag(ast_lowering::invalid_abi_clobber_abi)]
+#[diag(ast_lowering_invalid_abi_clobber_abi)]
pub struct InvalidAbiClobberAbi {
#[primary_span]
pub abi_span: Span,
pub supported_abis: String,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::invalid_register)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_invalid_register)]
pub struct InvalidRegister<'a> {
#[primary_span]
pub op_span: Span,
@@ -200,8 +200,8 @@ pub struct InvalidRegister<'a> {
pub error: &'a str,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::invalid_register_class)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_invalid_register_class)]
pub struct InvalidRegisterClass<'a> {
#[primary_span]
pub op_span: Span,
@@ -209,61 +209,61 @@ pub struct InvalidRegisterClass<'a> {
pub error: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_lowering::invalid_asm_template_modifier_reg_class)]
+#[derive(Diagnostic)]
+#[diag(ast_lowering_invalid_asm_template_modifier_reg_class)]
pub struct InvalidAsmTemplateModifierRegClass {
#[primary_span]
- #[label(ast_lowering::template_modifier)]
+ #[label(ast_lowering_template_modifier)]
pub placeholder_span: Span,
- #[label(ast_lowering::argument)]
+ #[label(ast_lowering_argument)]
pub op_span: Span,
#[subdiagnostic]
pub sub: InvalidAsmTemplateModifierRegClassSub,
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub enum InvalidAsmTemplateModifierRegClassSub {
- #[note(ast_lowering::support_modifiers)]
+ #[note(ast_lowering_support_modifiers)]
SupportModifier { class_name: Symbol, modifiers: String },
- #[note(ast_lowering::does_not_support_modifiers)]
+ #[note(ast_lowering_does_not_support_modifiers)]
DoesNotSupportModifier { class_name: Symbol },
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::invalid_asm_template_modifier_const)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_invalid_asm_template_modifier_const)]
pub struct InvalidAsmTemplateModifierConst {
#[primary_span]
- #[label(ast_lowering::template_modifier)]
+ #[label(ast_lowering_template_modifier)]
pub placeholder_span: Span,
- #[label(ast_lowering::argument)]
+ #[label(ast_lowering_argument)]
pub op_span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::invalid_asm_template_modifier_sym)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_invalid_asm_template_modifier_sym)]
pub struct InvalidAsmTemplateModifierSym {
#[primary_span]
- #[label(ast_lowering::template_modifier)]
+ #[label(ast_lowering_template_modifier)]
pub placeholder_span: Span,
- #[label(ast_lowering::argument)]
+ #[label(ast_lowering_argument)]
pub op_span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::register_class_only_clobber)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_register_class_only_clobber)]
pub struct RegisterClassOnlyClobber {
#[primary_span]
pub op_span: Span,
pub reg_class_name: Symbol,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::register_conflict)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_register_conflict)]
pub struct RegisterConflict<'a> {
#[primary_span]
- #[label(ast_lowering::register1)]
+ #[label(ast_lowering_register1)]
pub op_span1: Span,
- #[label(ast_lowering::register2)]
+ #[label(ast_lowering_register2)]
pub op_span2: Span,
pub reg1_name: &'a str,
pub reg2_name: &'a str,
@@ -271,14 +271,14 @@ pub struct RegisterConflict<'a> {
pub in_out: Option<Span>,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
+#[derive(Diagnostic, Clone, Copy)]
#[help]
-#[diag(ast_lowering::sub_tuple_binding)]
+#[diag(ast_lowering_sub_tuple_binding)]
pub struct SubTupleBinding<'a> {
#[primary_span]
#[label]
#[suggestion_verbose(
- ast_lowering::sub_tuple_binding_suggestion,
+ ast_lowering_sub_tuple_binding_suggestion,
code = "..",
applicability = "maybe-incorrect"
)]
@@ -288,57 +288,57 @@ pub struct SubTupleBinding<'a> {
pub ctx: &'a str,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::extra_double_dot)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_extra_double_dot)]
pub struct ExtraDoubleDot<'a> {
#[primary_span]
#[label]
pub span: Span,
- #[label(ast_lowering::previously_used_here)]
+ #[label(ast_lowering_previously_used_here)]
pub prev_span: Span,
pub ctx: &'a str,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
+#[derive(Diagnostic, Clone, Copy)]
#[note]
-#[diag(ast_lowering::misplaced_double_dot)]
+#[diag(ast_lowering_misplaced_double_dot)]
pub struct MisplacedDoubleDot {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::misplaced_relax_trait_bound)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_misplaced_relax_trait_bound)]
pub struct MisplacedRelaxTraitBound {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::not_supported_for_lifetime_binder_async_closure)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_not_supported_for_lifetime_binder_async_closure)]
pub struct NotSupportedForLifetimeBinderAsyncClosure {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::arbitrary_expression_in_pattern)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_arbitrary_expression_in_pattern)]
pub struct ArbitraryExpressionInPattern {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::inclusive_range_with_no_end)]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_inclusive_range_with_no_end)]
pub struct InclusiveRangeWithNoEnd {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic, Clone, Copy)]
-#[diag(ast_lowering::trait_fn_async, code = "E0706")]
+#[derive(Diagnostic, Clone, Copy)]
+#[diag(ast_lowering_trait_fn_async, code = "E0706")]
#[note]
-#[note(ast_lowering::note2)]
+#[note(note2)]
pub struct TraitFnAsync {
#[primary_span]
pub fn_span: Span,
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 7b8070d3c..ec9c39350 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -60,7 +60,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ExprKind::Call(f, self.lower_exprs(args))
}
}
- ExprKind::MethodCall(ref seg, ref args, span) => {
+ ExprKind::MethodCall(ref seg, ref receiver, ref args, span) => {
let hir_seg = self.arena.alloc(self.lower_path_segment(
e.span,
seg,
@@ -68,9 +68,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
ParenthesizedGenericArgs::Err,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
));
- let receiver = self.lower_expr(&args[0]);
+ let receiver = self.lower_expr(receiver);
let args =
- self.arena.alloc_from_iter(args[1..].iter().map(|x| self.lower_expr_mut(x)));
+ self.arena.alloc_from_iter(args.iter().map(|x| self.lower_expr_mut(x)));
hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(span))
}
ExprKind::Binary(binop, ref lhs, ref rhs) => {
@@ -359,7 +359,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let node_id = self.next_node_id();
// Add a definition for the in-band const def.
- self.create_def(parent_def_id, node_id, DefPathData::AnonConst);
+ self.create_def(parent_def_id.def_id, node_id, DefPathData::AnonConst);
let anon_const = AnonConst { id: node_id, value: arg };
generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
@@ -387,32 +387,58 @@ impl<'hir> LoweringContext<'_, 'hir> {
then: &Block,
else_opt: Option<&Expr>,
) -> hir::ExprKind<'hir> {
- let lowered_cond = self.lower_expr(cond);
- let new_cond = self.manage_let_cond(lowered_cond);
+ let lowered_cond = self.lower_cond(cond);
let then_expr = self.lower_block_expr(then);
if let Some(rslt) = else_opt {
- hir::ExprKind::If(new_cond, self.arena.alloc(then_expr), Some(self.lower_expr(rslt)))
+ hir::ExprKind::If(
+ lowered_cond,
+ self.arena.alloc(then_expr),
+ Some(self.lower_expr(rslt)),
+ )
} else {
- hir::ExprKind::If(new_cond, self.arena.alloc(then_expr), None)
+ hir::ExprKind::If(lowered_cond, self.arena.alloc(then_expr), None)
}
}
- // If `cond` kind is `let`, returns `let`. Otherwise, wraps and returns `cond`
- // in a temporary block.
- fn manage_let_cond(&mut self, cond: &'hir hir::Expr<'hir>) -> &'hir hir::Expr<'hir> {
- fn has_let_expr<'hir>(expr: &'hir hir::Expr<'hir>) -> bool {
- match expr.kind {
- hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
- hir::ExprKind::Let(..) => true,
+ // Lowers a condition (i.e. `cond` in `if cond` or `while cond`), wrapping it in a terminating scope
+ // so that temporaries created in the condition don't live beyond it.
+ fn lower_cond(&mut self, cond: &Expr) -> &'hir hir::Expr<'hir> {
+ fn has_let_expr(expr: &Expr) -> bool {
+ match &expr.kind {
+ ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
+ ExprKind::Let(..) => true,
_ => false,
}
}
- if has_let_expr(cond) {
- cond
- } else {
- let reason = DesugaringKind::CondTemporary;
- let span_block = self.mark_span_with_reason(reason, cond.span, None);
- self.expr_drop_temps(span_block, cond, AttrVec::new())
+
+ // We have to take special care for `let` exprs in the condition, e.g. in
+ // `if let pat = val` or `if foo && let pat = val`, as we _do_ want `val` to live beyond the
+ // condition in this case.
+ //
+ // In order to mantain the drop behavior for the non `let` parts of the condition,
+ // we still wrap them in terminating scopes, e.g. `if foo && let pat = val` essentially
+ // gets transformed into `if { let _t = foo; _t } && let pat = val`
+ match &cond.kind {
+ ExprKind::Binary(op @ Spanned { node: ast::BinOpKind::And, .. }, lhs, rhs)
+ if has_let_expr(cond) =>
+ {
+ let op = self.lower_binop(*op);
+ let lhs = self.lower_cond(lhs);
+ let rhs = self.lower_cond(rhs);
+
+ self.arena.alloc(self.expr(
+ cond.span,
+ hir::ExprKind::Binary(op, lhs, rhs),
+ AttrVec::new(),
+ ))
+ }
+ ExprKind::Let(..) => self.lower_expr(cond),
+ _ => {
+ let cond = self.lower_expr(cond);
+ let reason = DesugaringKind::CondTemporary;
+ let span_block = self.mark_span_with_reason(reason, cond.span, None);
+ self.expr_drop_temps(span_block, cond, AttrVec::new())
+ }
}
}
@@ -439,14 +465,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
body: &Block,
opt_label: Option<Label>,
) -> hir::ExprKind<'hir> {
- let lowered_cond = self.with_loop_condition_scope(|t| t.lower_expr(cond));
- let new_cond = self.manage_let_cond(lowered_cond);
+ let lowered_cond = self.with_loop_condition_scope(|t| t.lower_cond(cond));
let then = self.lower_block_expr(body);
let expr_break = self.expr_break(span, AttrVec::new());
let stmt_break = self.stmt_expr(span, expr_break);
let else_blk = self.block_all(span, arena_vec![self; stmt_break], None);
let else_expr = self.arena.alloc(self.expr_block(else_blk, AttrVec::new()));
- let if_kind = hir::ExprKind::If(new_cond, self.arena.alloc(then), Some(else_expr));
+ let if_kind = hir::ExprKind::If(lowered_cond, self.arena.alloc(then), Some(else_expr));
let if_expr = self.expr(span, if_kind, AttrVec::new());
let block = self.block_expr(self.arena.alloc(if_expr));
let span = self.lower_span(span.with_hi(cond.span.hi()));
@@ -1044,9 +1069,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
if let ExprKind::Path(qself, path) = &expr.kind {
// Does the path resolve to something disallowed in a tuple struct/variant pattern?
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
- if partial_res.unresolved_segments() == 0
- && !partial_res.base_res().expected_in_tuple_struct_pat()
- {
+ if let Some(res) = partial_res.full_res() && !res.expected_in_tuple_struct_pat() {
return None;
}
}
@@ -1066,9 +1089,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
if let ExprKind::Path(qself, path) = &expr.kind {
// Does the path resolve to something disallowed in a unit struct/variant pattern?
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
- if partial_res.unresolved_segments() == 0
- && !partial_res.base_res().expected_in_unit_struct_pat()
- {
+ if let Some(res) = partial_res.full_res() && !res.expected_in_unit_struct_pat() {
return None;
}
}
@@ -1609,11 +1630,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
/// Desugar `ExprKind::Yeet` from: `do yeet <expr>` into:
- /// ```rust
+ /// ```ignore(illustrative)
/// // If there is an enclosing `try {...}`:
- /// break 'catch_target FromResidual::from_residual(Yeet(residual)),
+ /// break 'catch_target FromResidual::from_residual(Yeet(residual));
/// // Otherwise:
- /// return FromResidual::from_residual(Yeet(residual)),
+ /// return FromResidual::from_residual(Yeet(residual));
/// ```
/// But to simplify this, there's a `from_yeet` lang item function which
/// handles the combined `FromResidual::from_residual(Yeet(residual))`.
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 85846b567..f1851d7b4 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -24,7 +24,7 @@ pub(super) struct NodeCollector<'a, 'hir> {
/// The parent of this node
parent_node: hir::ItemLocalId,
- owner: LocalDefId,
+ owner: OwnerId,
definitions: &'a definitions::Definitions,
}
@@ -81,9 +81,9 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
self.source_map.span_to_diagnostic_string(span),
node,
- self.definitions.def_path(self.owner).to_string_no_crate_verbose(),
+ self.definitions.def_path(self.owner.def_id).to_string_no_crate_verbose(),
self.owner,
- self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(),
+ self.definitions.def_path(hir_id.owner.def_id).to_string_no_crate_verbose(),
hir_id.owner,
)
}
@@ -112,19 +112,19 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
fn visit_nested_item(&mut self, item: ItemId) {
debug!("visit_nested_item: {:?}", item);
- self.insert_nested(item.def_id);
+ self.insert_nested(item.owner_id.def_id);
}
fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
- self.insert_nested(item_id.def_id);
+ self.insert_nested(item_id.owner_id.def_id);
}
fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
- self.insert_nested(item_id.def_id);
+ self.insert_nested(item_id.owner_id.def_id);
}
fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
- self.insert_nested(foreign_id.def_id);
+ self.insert_nested(foreign_id.owner_id.def_id);
}
fn visit_nested_body(&mut self, id: BodyId) {
@@ -143,7 +143,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
#[instrument(level = "debug", skip(self))]
fn visit_item(&mut self, i: &'hir Item<'hir>) {
- debug_assert_eq!(i.def_id, self.owner);
+ debug_assert_eq!(i.owner_id, self.owner);
self.with_parent(i.hir_id(), |this| {
if let ItemKind::Struct(ref struct_def, _) = i.kind {
// If this is a tuple or unit-like struct, register the constructor.
@@ -157,7 +157,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
#[instrument(level = "debug", skip(self))]
fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
- debug_assert_eq!(fi.def_id, self.owner);
+ debug_assert_eq!(fi.owner_id, self.owner);
self.with_parent(fi.hir_id(), |this| {
intravisit::walk_foreign_item(this, fi);
});
@@ -176,7 +176,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
#[instrument(level = "debug", skip(self))]
fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
- debug_assert_eq!(ti.def_id, self.owner);
+ debug_assert_eq!(ti.owner_id, self.owner);
self.with_parent(ti.hir_id(), |this| {
intravisit::walk_trait_item(this, ti);
});
@@ -184,7 +184,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
#[instrument(level = "debug", skip(self))]
fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
- debug_assert_eq!(ii.def_id, self.owner);
+ debug_assert_eq!(ii.owner_id, self.owner);
self.with_parent(ii.hir_id(), |this| {
intravisit::walk_impl_item(this, ii);
});
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 550833275..76316a574 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1,4 +1,4 @@
-use super::errors::{InvalidAbi, MisplacedRelaxTraitBound};
+use super::errors::{InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
use super::ResolverAstLoweringExt;
use super::{Arena, AstOwner, ImplTraitContext, ImplTraitPosition};
use super::{FnDeclKind, LoweringContext, ParamMode};
@@ -14,9 +14,10 @@ use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::PredicateOrigin;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::ty::{DefIdTree, ResolverAstLowering, TyCtxt};
+use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
use rustc_target::spec::abi;
use smallvec::{smallvec, SmallVec};
@@ -67,7 +68,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
bodies: Vec::new(),
attrs: SortedMap::default(),
children: FxHashMap::default(),
- current_hir_id_owner: CRATE_DEF_ID,
+ current_hir_id_owner: hir::CRATE_OWNER_ID,
item_local_id_counter: hir::ItemLocalId::new(0),
node_id_to_local_id: Default::default(),
local_id_to_def_id: SortedMap::new(),
@@ -176,7 +177,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
pub(super) fn lower_item_ref(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> {
- let mut node_ids = smallvec![hir::ItemId { def_id: self.local_def_id(i.id) }];
+ let mut node_ids =
+ smallvec![hir::ItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }];
if let ItemKind::Use(ref use_tree) = &i.kind {
self.lower_item_id_use_tree(use_tree, i.id, &mut node_ids);
}
@@ -192,7 +194,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
match tree.kind {
UseTreeKind::Nested(ref nested_vec) => {
for &(ref nested, id) in nested_vec {
- vec.push(hir::ItemId { def_id: self.local_def_id(id) });
+ vec.push(hir::ItemId {
+ owner_id: hir::OwnerId { def_id: self.local_def_id(id) },
+ });
self.lower_item_id_use_tree(nested, id, vec);
}
}
@@ -201,7 +205,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
for (_, &id) in
iter::zip(self.expect_full_res_from_use(base_id).skip(1), &[id1, id2])
{
- vec.push(hir::ItemId { def_id: self.local_def_id(id) });
+ vec.push(hir::ItemId {
+ owner_id: hir::OwnerId { def_id: self.local_def_id(id) },
+ });
}
}
}
@@ -214,7 +220,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let attrs = self.lower_attrs(hir_id, &i.attrs);
let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind);
let item = hir::Item {
- def_id: hir_id.expect_owner(),
+ owner_id: hir_id.expect_owner(),
ident: self.lower_ident(ident),
kind,
vis_span,
@@ -539,7 +545,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
let ident = *ident;
let mut path = path.clone();
for seg in &mut path.segments {
- seg.id = self.next_node_id();
+ // Give the cloned segment the same resolution information
+ // as the old one (this is needed for stability checking).
+ let new_id = self.next_node_id();
+ self.resolver.clone_res(seg.id, new_id);
+ seg.id = new_id;
}
let span = path.span;
@@ -552,7 +562,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
let item = hir::Item {
- def_id: new_id,
+ owner_id: hir::OwnerId { def_id: new_id },
ident: this.lower_ident(ident),
kind,
vis_span,
@@ -608,7 +618,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
// Give the segments new node-ids since they are being cloned.
for seg in &mut prefix.segments {
- seg.id = self.next_node_id();
+ // Give the cloned segment the same resolution information
+ // as the old one (this is needed for stability checking).
+ let new_id = self.next_node_id();
+ self.resolver.clone_res(seg.id, new_id);
+ seg.id = new_id;
}
// Each `use` import is an item and thus are owners of the
@@ -626,7 +640,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
let item = hir::Item {
- def_id: new_hir_id,
+ owner_id: hir::OwnerId { def_id: new_hir_id },
ident: this.lower_ident(ident),
kind,
vis_span,
@@ -646,10 +660,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> {
let hir_id = self.lower_node_id(i.id);
- let def_id = hir_id.expect_owner();
+ let owner_id = hir_id.expect_owner();
self.lower_attrs(hir_id, &i.attrs);
let item = hir::ForeignItem {
- def_id,
+ owner_id,
ident: self.lower_ident(i.ident),
kind: match i.kind {
ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
@@ -688,7 +702,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef {
hir::ForeignItemRef {
- id: hir::ForeignItemId { def_id: self.local_def_id(i.id) },
+ id: hir::ForeignItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
ident: self.lower_ident(i.ident),
span: self.lower_span(i.span),
}
@@ -798,7 +812,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true)
}
- AssocItemKind::TyAlias(box TyAlias {
+ AssocItemKind::Type(box TyAlias {
ref generics,
where_clauses,
ref bounds,
@@ -831,7 +845,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_attrs(hir_id, &i.attrs);
let item = hir::TraitItem {
- def_id: trait_item_def_id,
+ owner_id: trait_item_def_id,
ident: self.lower_ident(i.ident),
generics,
kind,
@@ -844,13 +858,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
let kind = match &i.kind {
AssocItemKind::Const(..) => hir::AssocItemKind::Const,
- AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type,
+ AssocItemKind::Type(..) => hir::AssocItemKind::Type,
AssocItemKind::Fn(box Fn { sig, .. }) => {
hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
}
AssocItemKind::MacCall(..) => unimplemented!(),
};
- let id = hir::TraitItemId { def_id: self.local_def_id(i.id) };
+ let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
hir::TraitItemRef {
id,
ident: self.lower_ident(i.ident),
@@ -892,7 +906,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
(generics, hir::ImplItemKind::Fn(sig, body_id))
}
- AssocItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => {
+ AssocItemKind::Type(box TyAlias { generics, where_clauses, ty, .. }) => {
let mut generics = generics.clone();
add_ty_alias_where_clause(&mut generics, *where_clauses, false);
self.lower_generics(
@@ -902,11 +916,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|this| match ty {
None => {
let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err));
- hir::ImplItemKind::TyAlias(ty)
+ hir::ImplItemKind::Type(ty)
}
Some(ty) => {
let ty = this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy);
- hir::ImplItemKind::TyAlias(ty)
+ hir::ImplItemKind::Type(ty)
}
},
)
@@ -917,7 +931,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let hir_id = self.lower_node_id(i.id);
self.lower_attrs(hir_id, &i.attrs);
let item = hir::ImplItem {
- def_id: hir_id.expect_owner(),
+ owner_id: hir_id.expect_owner(),
ident: self.lower_ident(i.ident),
generics,
kind,
@@ -930,18 +944,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
hir::ImplItemRef {
- id: hir::ImplItemId { def_id: self.local_def_id(i.id) },
+ id: hir::ImplItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
ident: self.lower_ident(i.ident),
span: self.lower_span(i.span),
kind: match &i.kind {
AssocItemKind::Const(..) => hir::AssocItemKind::Const,
- AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type,
+ AssocItemKind::Type(..) => hir::AssocItemKind::Type,
AssocItemKind::Fn(box Fn { sig, .. }) => {
hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
}
AssocItemKind::MacCall(..) => unimplemented!(),
},
- trait_item_def_id: self.resolver.get_partial_res(i.id).map(|r| r.base_res().def_id()),
+ trait_item_def_id: self
+ .resolver
+ .get_partial_res(i.id)
+ .map(|r| r.expect_full_res().def_id()),
}
}
@@ -1049,9 +1066,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
asyncness: Async,
body: Option<&Block>,
) -> hir::BodyId {
- let closure_id = match asyncness {
- Async::Yes { closure_id, .. } => closure_id,
- Async::No => return self.lower_fn_body_block(span, decl, body),
+ let (closure_id, body) = match (asyncness, body) {
+ (Async::Yes { closure_id, .. }, Some(body)) => (closure_id, body),
+ _ => return self.lower_fn_body_block(span, decl, body),
};
self.lower_body(|this| {
@@ -1193,16 +1210,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
parameters.push(new_parameter);
}
- let body_span = body.map_or(span, |b| b.span);
let async_expr = this.make_async_expr(
CaptureBy::Value,
closure_id,
None,
- body_span,
+ body.span,
hir::AsyncGeneratorKind::Fn,
|this| {
// Create a block from the user's function body:
- let user_body = this.lower_block_expr_opt(body_span, body);
+ let user_body = this.lower_block_expr(body);
// Transform into `drop-temps { <user-body> }`, an expression:
let desugared_span =
@@ -1234,7 +1250,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
(
this.arena.alloc_from_iter(parameters),
- this.expr(body_span, async_expr, AttrVec::new()),
+ this.expr(body.span, async_expr, AttrVec::new()),
)
})
}
@@ -1280,10 +1296,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
fn error_on_invalid_abi(&self, abi: StrLit) {
+ let abi_names = abi::enabled_names(self.tcx.features(), abi.span)
+ .iter()
+ .map(|s| Symbol::intern(s))
+ .collect::<Vec<_>>();
+ let suggested_name = find_best_match_for_name(&abi_names, abi.symbol_unescaped, None);
self.tcx.sess.emit_err(InvalidAbi {
+ abi: abi.symbol_unescaped,
span: abi.span,
- abi: abi.symbol,
- valid_abis: abi::all_names().join(", "),
+ suggestion: suggested_name.map(|suggested_name| InvalidAbiSuggestion {
+ span: abi.span,
+ suggestion: format!("\"{suggested_name}\""),
+ }),
+ command: "rustc --print=calling-conventions".to_string(),
});
}
@@ -1335,9 +1360,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
match self
.resolver
.get_partial_res(bound_pred.bounded_ty.id)
- .map(|d| (d.base_res(), d.unresolved_segments()))
+ .and_then(|r| r.full_res())
{
- Some((Res::Def(DefKind::TyParam, def_id), 0))
+ Some(Res::Def(DefKind::TyParam, def_id))
if bound_pred.bound_generic_params.is_empty() =>
{
generics
@@ -1464,6 +1489,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let bounded_ty =
self.ty_path(ty_id, param_span, hir::QPath::Resolved(None, ty_path));
Some(hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+ hir_id: self.next_id(),
bounded_ty: self.arena.alloc(bounded_ty),
bounds,
span,
@@ -1494,6 +1520,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ref bounds,
span,
}) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+ hir_id: self.next_id(),
bound_generic_params: self.lower_generic_params(bound_generic_params),
bounded_ty: self
.lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 9012aa704..ff29d15f1 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -32,7 +32,6 @@
#![feature(box_patterns)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(never_type)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
@@ -62,8 +61,8 @@ use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::definitions::DefPathData;
use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::span_bug;
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
+use rustc_middle::{bug, span_bug};
use rustc_session::parse::feature_err;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::DesugaringKind;
@@ -126,7 +125,7 @@ struct LoweringContext<'a, 'hir> {
is_in_trait_impl: bool,
is_in_dyn_type: bool,
- current_hir_id_owner: LocalDefId,
+ current_hir_id_owner: hir::OwnerId,
item_local_id_counter: hir::ItemLocalId,
local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>,
trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>,
@@ -161,6 +160,10 @@ trait ResolverAstLoweringExt {
fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
+ // Clones the resolution (if any) on 'source' and applies it
+ // to 'target'. Used when desugaring a `UseTreeKind::Nested` to
+ // multiple `UseTreeKind::Simple`s
+ fn clone_res(&mut self, source: NodeId, target: NodeId);
fn get_label_res(&self, id: NodeId) -> Option<NodeId>;
fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
@@ -176,12 +179,7 @@ impl ResolverAstLoweringExt for ResolverAstLowering {
return None;
}
- let partial_res = self.partial_res_map.get(&expr.id)?;
- if partial_res.unresolved_segments() != 0 {
- return None;
- }
-
- if let Res::Def(DefKind::Fn, def_id) = partial_res.base_res() {
+ if let Res::Def(DefKind::Fn, def_id) = self.partial_res_map.get(&expr.id)?.full_res()? {
// We only support cross-crate argument rewriting. Uses
// within the same crate should be updated to use the new
// const generics style.
@@ -198,6 +196,12 @@ impl ResolverAstLoweringExt for ResolverAstLowering {
None
}
+ fn clone_res(&mut self, source: NodeId, target: NodeId) {
+ if let Some(res) = self.partial_res_map.get(&source) {
+ self.partial_res_map.insert(target, *res);
+ }
+ }
+
/// Obtains resolution for a `NodeId` with a single resolution.
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
self.partial_res_map.get(&id).copied()
@@ -324,17 +328,20 @@ enum FnDeclKind {
}
impl FnDeclKind {
- fn impl_trait_return_allowed(&self, tcx: TyCtxt<'_>) -> bool {
+ fn impl_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool {
match self {
FnDeclKind::Fn | FnDeclKind::Inherent => true,
FnDeclKind::Impl if tcx.features().return_position_impl_trait_in_trait => true,
+ FnDeclKind::Trait if tcx.features().return_position_impl_trait_in_trait => true,
_ => false,
}
}
- fn impl_trait_in_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool {
+ fn async_fn_allowed(&self, tcx: TyCtxt<'_>) -> bool {
match self {
- FnDeclKind::Trait if tcx.features().return_position_impl_trait_in_trait => true,
+ FnDeclKind::Fn | FnDeclKind::Inherent => true,
+ FnDeclKind::Impl if tcx.features().async_fn_in_trait => true,
+ FnDeclKind::Trait if tcx.features().async_fn_in_trait => true,
_ => false,
}
}
@@ -572,7 +579,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let current_node_ids = std::mem::take(&mut self.node_id_to_local_id);
let current_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id);
let current_trait_map = std::mem::take(&mut self.trait_map);
- let current_owner = std::mem::replace(&mut self.current_hir_id_owner, def_id);
+ let current_owner =
+ std::mem::replace(&mut self.current_hir_id_owner, hir::OwnerId { def_id });
let current_local_counter =
std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1));
let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
@@ -587,7 +595,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
debug_assert_eq!(_old, None);
let item = f(self);
- debug_assert_eq!(def_id, item.def_id());
+ debug_assert_eq!(def_id, item.def_id().def_id);
// `f` should have consumed all the elements in these vectors when constructing `item`.
debug_assert!(self.impl_trait_defs.is_empty());
debug_assert!(self.impl_trait_bounds.is_empty());
@@ -753,12 +761,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
fn expect_full_res(&mut self, id: NodeId) -> Res<NodeId> {
- self.resolver.get_partial_res(id).map_or(Res::Err, |pr| {
- if pr.unresolved_segments() != 0 {
- panic!("path not fully resolved: {:?}", pr);
- }
- pr.base_res()
- })
+ self.resolver.get_partial_res(id).map_or(Res::Err, |pr| pr.expect_full_res())
}
fn expect_full_res_from_use(&mut self, id: NodeId) -> impl Iterator<Item = Res<NodeId>> {
@@ -786,7 +789,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// Mark a span as relative to the current owning item.
fn lower_span(&self, span: Span) -> Span {
if self.tcx.sess.opts.unstable_opts.incremental_relative_spans {
- span.with_parent(Some(self.current_hir_id_owner))
+ span.with_parent(Some(self.current_hir_id_owner.def_id))
} else {
// Do not make spans relative when not using incremental compilation.
span
@@ -812,7 +815,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
LifetimeRes::Fresh { param, .. } => {
// Late resolution delegates to us the creation of the `LocalDefId`.
let _def_id = self.create_def(
- self.current_hir_id_owner,
+ self.current_hir_id_owner.def_id,
param,
DefPathData::LifetimeNs(kw::UnderscoreLifetime),
);
@@ -1060,9 +1063,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by
// constructing the HIR for `impl bounds...` and then lowering that.
- let parent_def_id = self.current_hir_id_owner;
let impl_trait_node_id = self.next_node_id();
- self.create_def(parent_def_id, impl_trait_node_id, DefPathData::ImplTrait);
self.with_dyn_type_scope(false, |this| {
let node_id = this.next_node_id();
@@ -1140,8 +1141,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// type and value namespaces. If we resolved the path in the value namespace, we
// transform it into a generic const argument.
TyKind::Path(ref qself, ref path) => {
- if let Some(partial_res) = self.resolver.get_partial_res(ty.id) {
- let res = partial_res.base_res();
+ 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) {
debug!(
"lower_generic_arg: Lowering type argument as const argument: {:?}",
@@ -1154,7 +1158,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let node_id = self.next_node_id();
// Add a definition for the in-band const def.
- self.create_def(parent_def_id, node_id, DefPathData::AnonConst);
+ self.create_def(
+ parent_def_id.def_id,
+ node_id,
+ DefPathData::AnonConst,
+ );
let span = self.lower_span(ty.span);
let path_expr = Expr {
@@ -1204,8 +1212,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// by `ty_path`.
if qself.is_none()
&& let Some(partial_res) = self.resolver.get_partial_res(t.id)
- && partial_res.unresolved_segments() == 0
- && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
+ && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res()
{
let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
let poly_trait_ref = this.ast_arena.ptr.alloc(PolyTraitRef {
@@ -1349,9 +1356,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
def_node_id,
bounds,
false,
- &ImplTraitContext::TypeAliasesOpaqueTy,
+ itctx,
),
ImplTraitContext::Universal => {
+ self.create_def(
+ self.current_hir_id_owner.def_id,
+ def_node_id,
+ DefPathData::ImplTrait,
+ );
let span = t.span;
let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
let (param, bounds, path) =
@@ -1445,7 +1457,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// frequently opened issues show.
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
- let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
+ let opaque_ty_def_id = match origin {
+ hir::OpaqueTyOrigin::TyAlias => self.create_def(
+ self.current_hir_id_owner.def_id,
+ opaque_ty_node_id,
+ DefPathData::ImplTrait,
+ ),
+ hir::OpaqueTyOrigin::FnReturn(fn_def_id) => {
+ self.create_def(fn_def_id, opaque_ty_node_id, DefPathData::ImplTrait)
+ }
+ hir::OpaqueTyOrigin::AsyncFn(..) => bug!("unreachable"),
+ };
debug!(?opaque_ty_def_id);
// Contains the new lifetime definitions created for the TAIT (if any).
@@ -1551,7 +1573,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
debug!(?lifetimes);
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
- hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes, in_trait)
+ hir::TyKind::OpaqueDef(
+ hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
+ lifetimes,
+ in_trait,
+ )
}
/// Registers a new opaque type with the proper `NodeId`s and
@@ -1567,7 +1593,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// Generate an `type Foo = impl Trait;` declaration.
trace!("registering opaque type with id {:#?}", opaque_ty_id);
let opaque_ty_item = hir::Item {
- def_id: opaque_ty_id,
+ owner_id: hir::OwnerId { def_id: opaque_ty_id },
ident: Ident::empty(),
kind: opaque_ty_item_kind,
vis_span: self.lower_span(span.shrink_to_lo()),
@@ -1701,62 +1727,38 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}));
let output = if let Some((ret_id, span)) = make_ret_async {
- match kind {
- FnDeclKind::Trait => {
- if !kind.impl_trait_in_trait_allowed(self.tcx) {
+ if !kind.async_fn_allowed(self.tcx) {
+ match kind {
+ FnDeclKind::Trait | FnDeclKind::Impl => {
self.tcx
.sess
.create_feature_err(
TraitFnAsync { fn_span, span },
- sym::return_position_impl_trait_in_trait,
+ sym::async_fn_in_trait,
)
.emit();
}
- self.lower_async_fn_ret_ty(
- &decl.output,
- fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
- ret_id,
- true,
- )
- }
- _ => {
- if !kind.impl_trait_return_allowed(self.tcx) {
- if kind == FnDeclKind::Impl {
- self.tcx
- .sess
- .create_feature_err(
- TraitFnAsync { fn_span, span },
- sym::return_position_impl_trait_in_trait,
- )
- .emit();
- } else {
- self.tcx.sess.emit_err(TraitFnAsync { fn_span, span });
- }
+ _ => {
+ self.tcx.sess.emit_err(TraitFnAsync { fn_span, span });
}
- self.lower_async_fn_ret_ty(
- &decl.output,
- fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
- ret_id,
- false,
- )
}
}
+
+ self.lower_async_fn_ret_ty(
+ &decl.output,
+ fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
+ ret_id,
+ matches!(kind, FnDeclKind::Trait),
+ )
} else {
match decl.output {
FnRetTy::Ty(ref ty) => {
let mut context = match fn_node_id {
- Some(fn_node_id) if kind.impl_trait_return_allowed(self.tcx) => {
- let fn_def_id = self.local_def_id(fn_node_id);
- ImplTraitContext::ReturnPositionOpaqueTy {
- origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
- in_trait: false,
- }
- }
- Some(fn_node_id) if kind.impl_trait_in_trait_allowed(self.tcx) => {
+ Some(fn_node_id) if kind.impl_trait_allowed(self.tcx) => {
let fn_def_id = self.local_def_id(fn_node_id);
ImplTraitContext::ReturnPositionOpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
- in_trait: true,
+ in_trait: matches!(kind, FnDeclKind::Trait),
}
}
_ => ImplTraitContext::Disallowed(match kind {
@@ -1950,9 +1952,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let future_bound = this.lower_async_fn_output_type_to_future_bound(
output,
span,
- ImplTraitContext::ReturnPositionOpaqueTy {
- origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
- in_trait,
+ if in_trait && !this.tcx.features().return_position_impl_trait_in_trait {
+ ImplTraitContext::Disallowed(ImplTraitPosition::TraitReturn)
+ } else {
+ ImplTraitContext::ReturnPositionOpaqueTy {
+ origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
+ in_trait,
+ }
},
);
@@ -2038,7 +2044,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// async fn, so the *type parameters* are inherited. It's
// only the lifetime parameters that we must supply.
let opaque_ty_ref = hir::TyKind::OpaqueDef(
- hir::ItemId { def_id: opaque_ty_def_id },
+ hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
generic_args,
in_trait,
);
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 1ea76fdbf..1af1633b5 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -239,7 +239,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ident: Ident,
lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
) -> hir::PatKind<'hir> {
- match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
+ match self.resolver.get_partial_res(p.id).map(|d| d.expect_full_res()) {
// `None` can occur in body-less function signatures
res @ (None | Some(Res::Local(_))) => {
let canonical_id = match res {
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 6bb1bb9ea..888776ccc 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -29,11 +29,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let partial_res =
self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
+ let base_res = partial_res.base_res();
+ let unresolved_segments = partial_res.unresolved_segments();
let path_span_lo = p.span.shrink_to_lo();
- let proj_start = p.segments.len() - partial_res.unresolved_segments();
+ let proj_start = p.segments.len() - unresolved_segments;
let path = self.arena.alloc(hir::Path {
- res: self.lower_res(partial_res.base_res()),
+ res: self.lower_res(base_res),
segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map(
|(i, segment)| {
let param_mode = match (qself_position, param_mode) {
@@ -46,7 +48,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
_ => param_mode,
};
- let parenthesized_generic_args = match partial_res.base_res() {
+ let parenthesized_generic_args = match base_res {
// `a::b::Trait(Args)`
Res::Def(DefKind::Trait, _) if i + 1 == proj_start => {
ParenthesizedGenericArgs::Ok
@@ -83,7 +85,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// Simple case, either no projections, or only fully-qualified.
// E.g., `std::mem::size_of` or `<I as Iterator>::Item`.
- if partial_res.unresolved_segments() == 0 {
+ if unresolved_segments == 0 {
return hir::QPath::Resolved(qself, path);
}
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index b1d10e07a..036643244 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -14,6 +14,7 @@ use rustc_ast::*;
use rustc_ast_pretty::pprust::{self, State};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability};
+use rustc_macros::Subdiagnostic;
use rustc_parse::validate_attr;
use rustc_session::lint::builtin::{
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
@@ -38,6 +39,13 @@ enum SelfSemantic {
No,
}
+/// What is the context that prevents using `~const`?
+enum DisallowTildeConstContext<'a> {
+ TraitObject,
+ ImplTrait,
+ Fn(FnKind<'a>),
+}
+
struct AstValidator<'a> {
session: &'a Session,
@@ -56,7 +64,7 @@ struct AstValidator<'a> {
/// e.g., `impl Iterator<Item = impl Debug>`.
outer_impl_trait: Option<Span>,
- is_tilde_const_allowed: bool,
+ disallow_tilde_const: Option<DisallowTildeConstContext<'a>>,
/// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
/// or `Foo::Bar<impl Trait>`
@@ -93,18 +101,26 @@ impl<'a> AstValidator<'a> {
self.is_impl_trait_banned = old;
}
- fn with_tilde_const(&mut self, allowed: bool, f: impl FnOnce(&mut Self)) {
- let old = mem::replace(&mut self.is_tilde_const_allowed, allowed);
+ fn with_tilde_const(
+ &mut self,
+ disallowed: Option<DisallowTildeConstContext<'a>>,
+ f: impl FnOnce(&mut Self),
+ ) {
+ let old = mem::replace(&mut self.disallow_tilde_const, disallowed);
f(self);
- self.is_tilde_const_allowed = old;
+ self.disallow_tilde_const = old;
}
fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
- self.with_tilde_const(true, f)
+ self.with_tilde_const(None, f)
}
- fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
- self.with_tilde_const(false, f)
+ fn with_banned_tilde_const(
+ &mut self,
+ ctx: DisallowTildeConstContext<'a>,
+ f: impl FnOnce(&mut Self),
+ ) {
+ self.with_tilde_const(Some(ctx), f)
}
fn with_let_management(
@@ -154,7 +170,7 @@ impl<'a> AstValidator<'a> {
DEPRECATED_WHERE_CLAUSE_LOCATION,
id,
where_clauses.0.1,
- fluent::ast_passes::deprecated_where_clause_location,
+ fluent::ast_passes_deprecated_where_clause_location,
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
where_clauses.1.1.shrink_to_hi(),
suggestion,
@@ -172,7 +188,7 @@ impl<'a> AstValidator<'a> {
fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.outer_impl_trait, outer);
if outer.is_some() {
- self.with_banned_tilde_const(f);
+ self.with_banned_tilde_const(DisallowTildeConstContext::ImplTrait, f);
} else {
f(self);
}
@@ -197,7 +213,10 @@ impl<'a> AstValidator<'a> {
TyKind::ImplTrait(..) => {
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
}
- TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
+ TyKind::TraitObject(..) => self
+ .with_banned_tilde_const(DisallowTildeConstContext::TraitObject, |this| {
+ visit::walk_ty(this, t)
+ }),
TyKind::Path(ref qself, ref path) => {
// We allow these:
// - `Option<impl Trait>`
@@ -233,20 +252,6 @@ impl<'a> AstValidator<'a> {
}
}
- fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
- if let Some(ident) = field.ident {
- if ident.name == kw::Underscore {
- self.visit_vis(&field.vis);
- self.visit_ident(ident);
- self.visit_ty_common(&field.ty);
- self.walk_ty(&field.ty);
- walk_list!(self, visit_attribute, &field.attrs);
- return;
- }
- }
- self.visit_field_def(field);
- }
-
fn err_handler(&self) -> &rustc_errors::Handler {
&self.session.diagnostic()
}
@@ -987,8 +992,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
visit::walk_lifetime(self, lifetime);
}
- fn visit_field_def(&mut self, s: &'a FieldDef) {
- visit::walk_field_def(self, s)
+ fn visit_field_def(&mut self, field: &'a FieldDef) {
+ visit::walk_field_def(self, field)
}
fn visit_item(&mut self, item: &'a Item) {
@@ -1176,42 +1181,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.check_mod_file_item_asciionly(item.ident);
}
}
- ItemKind::Struct(ref vdata, ref generics) => match vdata {
- // Duplicating the `Visitor` logic allows catching all cases
- // of `Anonymous(Struct, Union)` outside of a field struct or union.
- //
- // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
- // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
- // it uses `visit_ty_common`, which doesn't contain that specific check.
- VariantData::Struct(ref fields, ..) => {
- self.visit_vis(&item.vis);
- self.visit_ident(item.ident);
- self.visit_generics(generics);
- self.with_banned_assoc_ty_bound(|this| {
- walk_list!(this, visit_struct_field_def, fields);
- });
- walk_list!(self, visit_attribute, &item.attrs);
- return;
- }
- _ => {}
- },
- ItemKind::Union(ref vdata, ref generics) => {
+ ItemKind::Union(ref vdata, ..) => {
if vdata.fields().is_empty() {
self.err_handler().span_err(item.span, "unions cannot have zero fields");
}
- match vdata {
- VariantData::Struct(ref fields, ..) => {
- self.visit_vis(&item.vis);
- self.visit_ident(item.ident);
- self.visit_generics(generics);
- self.with_banned_assoc_ty_bound(|this| {
- walk_list!(this, visit_struct_field_def, fields);
- });
- walk_list!(self, visit_attribute, &item.attrs);
- return;
- }
- _ => {}
- }
}
ItemKind::Const(def, .., None) => {
self.check_defaultness(item.span, def);
@@ -1411,13 +1384,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
);
err.emit();
}
- (_, TraitBoundModifier::MaybeConst) => {
- if !self.is_tilde_const_allowed {
- self.err_handler()
- .struct_span_err(bound.span(), "`~const` is not allowed here")
- .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
- .emit();
- }
+ (_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => {
+ let mut err = self.err_handler().struct_span_err(bound.span(), "`~const` is not allowed here");
+ match reason {
+ DisallowTildeConstContext::TraitObject => err.note("trait objects cannot have `~const` trait bounds"),
+ DisallowTildeConstContext::ImplTrait => err.note("`impl Trait`s cannot have `~const` trait bounds"),
+ DisallowTildeConstContext::Fn(FnKind::Closure(..)) => err.note("closures cannot have `~const` trait bounds"),
+ DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => err.span_note(ident.span, "this function is not `const`, so it cannot have `~const` trait bounds"),
+ };
+ err.emit();
}
(_, TraitBoundModifier::MaybeConstMaybe) => {
self.err_handler()
@@ -1524,10 +1499,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
let tilde_const_allowed =
- matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. }))
+ matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
- self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk));
+ let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
+
+ self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
}
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
@@ -1557,7 +1534,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
});
}
}
- AssocItemKind::TyAlias(box TyAlias {
+ AssocItemKind::Type(box TyAlias {
generics,
where_clauses,
where_predicates_split,
@@ -1596,7 +1573,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
match item.kind {
- AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
+ AssocItemKind::Type(box TyAlias { ref generics, ref bounds, ref ty, .. })
if ctxt == AssocCtxt::Trait =>
{
self.visit_vis(&item.vis);
@@ -1771,7 +1748,7 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
in_const_trait_impl: false,
has_proc_macro_decls: false,
outer_impl_trait: None,
- is_tilde_const_allowed: false,
+ disallow_tilde_const: None,
is_impl_trait_banned: false,
is_assoc_ty_bound_banned: false,
forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
@@ -1783,15 +1760,17 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
}
/// Used to forbid `let` expressions in certain syntactic locations.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Subdiagnostic)]
pub(crate) enum ForbiddenLetReason {
/// `let` is not valid and the source environment is not important
GenericForbidden,
/// A let chain with the `||` operator
- NotSupportedOr(Span),
+ #[note(not_supported_or)]
+ NotSupportedOr(#[primary_span] Span),
/// A let chain with invalid parentheses
///
/// For example, `let 1 = 1 && (expr && expr)` is allowed
/// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
- NotSupportedParentheses(Span),
+ #[note(not_supported_parentheses)]
+ NotSupportedParentheses(#[primary_span] Span),
}
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 4f3b09c58..59f582f10 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -1,13 +1,13 @@
//! Errors emitted by ast_passes.
-use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic};
-use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
+use rustc_errors::{fluent, AddToDiagnostic, Applicability, Diagnostic, SubdiagnosticMessage};
+use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{Span, Symbol};
use crate::ast_validation::ForbiddenLetReason;
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::forbidden_let)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_forbidden_let)]
#[note]
pub struct ForbiddenLet {
#[primary_span]
@@ -16,130 +16,116 @@ pub struct ForbiddenLet {
pub(crate) reason: ForbiddenLetReason,
}
-impl AddSubdiagnostic for ForbiddenLetReason {
- fn add_to_diagnostic(self, diag: &mut Diagnostic) {
- match self {
- Self::GenericForbidden => {}
- Self::NotSupportedOr(span) => {
- diag.span_note(span, fluent::ast_passes::not_supported_or);
- }
- Self::NotSupportedParentheses(span) => {
- diag.span_note(span, fluent::ast_passes::not_supported_parentheses);
- }
- }
- }
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::forbidden_let_stable)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_forbidden_let_stable)]
#[note]
pub struct ForbiddenLetStable {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::forbidden_assoc_constraint)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_forbidden_assoc_constraint)]
pub struct ForbiddenAssocConstraint {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::keyword_lifetime)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_keyword_lifetime)]
pub struct KeywordLifetime {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::invalid_label)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_invalid_label)]
pub struct InvalidLabel {
#[primary_span]
pub span: Span,
pub name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::invalid_visibility, code = "E0449")]
+#[derive(Diagnostic)]
+#[diag(ast_passes_invalid_visibility, code = "E0449")]
pub struct InvalidVisibility {
#[primary_span]
pub span: Span,
- #[label(ast_passes::implied)]
+ #[label(implied)]
pub implied: Option<Span>,
#[subdiagnostic]
pub note: Option<InvalidVisibilityNote>,
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub enum InvalidVisibilityNote {
- #[note(ast_passes::individual_impl_items)]
+ #[note(individual_impl_items)]
IndividualImplItems,
- #[note(ast_passes::individual_foreign_items)]
+ #[note(individual_foreign_items)]
IndividualForeignItems,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::trait_fn_const, code = "E0379")]
+#[derive(Diagnostic)]
+#[diag(ast_passes_trait_fn_const, code = "E0379")]
pub struct TraitFnConst {
#[primary_span]
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::forbidden_lifetime_bound)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_forbidden_lifetime_bound)]
pub struct ForbiddenLifetimeBound {
#[primary_span]
pub spans: Vec<Span>,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::forbidden_non_lifetime_param)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_forbidden_non_lifetime_param)]
pub struct ForbiddenNonLifetimeParam {
#[primary_span]
pub spans: Vec<Span>,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::fn_param_too_many)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_fn_param_too_many)]
pub struct FnParamTooMany {
#[primary_span]
pub span: Span,
pub max_num_args: usize,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::fn_param_c_var_args_only)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_fn_param_c_var_args_only)]
pub struct FnParamCVarArgsOnly {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::fn_param_c_var_args_not_last)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_fn_param_c_var_args_not_last)]
pub struct FnParamCVarArgsNotLast {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::fn_param_doc_comment)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_fn_param_doc_comment)]
pub struct FnParamDocComment {
#[primary_span]
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::fn_param_forbidden_attr)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_fn_param_forbidden_attr)]
pub struct FnParamForbiddenAttr {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::fn_param_forbidden_self)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_fn_param_forbidden_self)]
#[note]
pub struct FnParamForbiddenSelf {
#[primary_span]
@@ -147,8 +133,8 @@ pub struct FnParamForbiddenSelf {
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::forbidden_default)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_forbidden_default)]
pub struct ForbiddenDefault {
#[primary_span]
pub span: Span,
@@ -156,8 +142,8 @@ pub struct ForbiddenDefault {
pub def_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::assoc_const_without_body)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_assoc_const_without_body)]
pub struct AssocConstWithoutBody {
#[primary_span]
pub span: Span,
@@ -165,8 +151,8 @@ pub struct AssocConstWithoutBody {
pub replace_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::assoc_fn_without_body)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_assoc_fn_without_body)]
pub struct AssocFnWithoutBody {
#[primary_span]
pub span: Span,
@@ -174,8 +160,8 @@ pub struct AssocFnWithoutBody {
pub replace_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::assoc_type_without_body)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_assoc_type_without_body)]
pub struct AssocTypeWithoutBody {
#[primary_span]
pub span: Span,
@@ -183,8 +169,8 @@ pub struct AssocTypeWithoutBody {
pub replace_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::const_without_body)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_const_without_body)]
pub struct ConstWithoutBody {
#[primary_span]
pub span: Span,
@@ -192,8 +178,8 @@ pub struct ConstWithoutBody {
pub replace_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::static_without_body)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_static_without_body)]
pub struct StaticWithoutBody {
#[primary_span]
pub span: Span,
@@ -201,8 +187,8 @@ pub struct StaticWithoutBody {
pub replace_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::ty_alias_without_body)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_ty_alias_without_body)]
pub struct TyAliasWithoutBody {
#[primary_span]
pub span: Span,
@@ -210,8 +196,8 @@ pub struct TyAliasWithoutBody {
pub replace_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::fn_without_body)]
+#[derive(Diagnostic)]
+#[diag(ast_passes_fn_without_body)]
pub struct FnWithoutBody {
#[primary_span]
pub span: Span,
@@ -227,8 +213,11 @@ pub struct ExternBlockSuggestion {
pub abi: Option<Symbol>,
}
-impl AddSubdiagnostic for ExternBlockSuggestion {
- fn add_to_diagnostic(self, diag: &mut Diagnostic) {
+impl AddToDiagnostic for ExternBlockSuggestion {
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
let start_suggestion = if let Some(abi) = self.abi {
format!("extern \"{}\" {{", abi)
} else {
@@ -237,7 +226,7 @@ impl AddSubdiagnostic for ExternBlockSuggestion {
let end_suggestion = " }".to_owned();
diag.multipart_suggestion(
- fluent::ast_passes::extern_block_suggestion,
+ fluent::extern_block_suggestion,
vec![(self.start_span, start_suggestion), (self.end_span, end_suggestion)],
Applicability::MaybeIncorrect,
);
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index aeff73c5b..546010135 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -1,15 +1,15 @@
use rustc_ast as ast;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
-use rustc_ast::{PatKind, RangeEnd, VariantData};
+use rustc_ast::{PatKind, RangeEnd};
use rustc_errors::{struct_span_err, Applicability, StashKey};
-use rustc_feature::Features;
-use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
-use rustc_session::parse::{feature_err, feature_warn};
+use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
+use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
use rustc_session::Session;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;
use rustc_span::Span;
+use rustc_target::spec::abi;
macro_rules! gate_feature_fn {
($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{
@@ -84,210 +84,26 @@ impl<'a> PostExpansionVisitor<'a> {
}
}
- match symbol_unescaped.as_str() {
- // Stable
- "Rust" | "C" | "cdecl" | "stdcall" | "fastcall" | "aapcs" | "win64" | "sysv64"
- | "system" => {}
- "rust-intrinsic" => {
- gate_feature_post!(&self, intrinsics, span, "intrinsics are subject to change");
- }
- "platform-intrinsic" => {
- gate_feature_post!(
- &self,
- platform_intrinsics,
- span,
- "platform intrinsics are experimental and possibly buggy"
- );
- }
- "vectorcall" => {
- gate_feature_post!(
- &self,
- abi_vectorcall,
- span,
- "vectorcall is experimental and subject to change"
- );
- }
- "thiscall" => {
- gate_feature_post!(
- &self,
- abi_thiscall,
- span,
- "thiscall is experimental and subject to change"
- );
- }
- "rust-call" => {
- gate_feature_post!(
- &self,
- unboxed_closures,
- span,
- "rust-call ABI is subject to change"
- );
- }
- "rust-cold" => {
- gate_feature_post!(
- &self,
- rust_cold_cc,
- span,
- "rust-cold is experimental and subject to change"
- );
- }
- "ptx-kernel" => {
- gate_feature_post!(
- &self,
- abi_ptx,
- span,
- "PTX ABIs are experimental and subject to change"
- );
- }
- "unadjusted" => {
- gate_feature_post!(
- &self,
- abi_unadjusted,
- span,
- "unadjusted ABI is an implementation detail and perma-unstable"
- );
- }
- "msp430-interrupt" => {
- gate_feature_post!(
- &self,
- abi_msp430_interrupt,
- span,
- "msp430-interrupt ABI is experimental and subject to change"
- );
- }
- "x86-interrupt" => {
- gate_feature_post!(
- &self,
- abi_x86_interrupt,
- span,
- "x86-interrupt ABI is experimental and subject to change"
- );
- }
- "amdgpu-kernel" => {
- gate_feature_post!(
- &self,
- abi_amdgpu_kernel,
- span,
- "amdgpu-kernel ABI is experimental and subject to change"
- );
- }
- "avr-interrupt" | "avr-non-blocking-interrupt" => {
- gate_feature_post!(
- &self,
- abi_avr_interrupt,
- span,
- "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change"
- );
- }
- "efiapi" => {
- gate_feature_post!(
- &self,
- abi_efiapi,
- span,
- "efiapi ABI is experimental and subject to change"
- );
- }
- "C-cmse-nonsecure-call" => {
- gate_feature_post!(
- &self,
- abi_c_cmse_nonsecure_call,
+ match abi::is_enabled(&self.features, span, symbol_unescaped.as_str()) {
+ Ok(()) => (),
+ Err(abi::AbiDisabled::Unstable { feature, explain }) => {
+ feature_err_issue(
+ &self.sess.parse_sess,
+ feature,
span,
- "C-cmse-nonsecure-call ABI is experimental and subject to change"
- );
- }
- "C-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "C-unwind ABI is experimental and subject to change"
- );
- }
- "stdcall-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "stdcall-unwind ABI is experimental and subject to change"
- );
- }
- "system-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "system-unwind ABI is experimental and subject to change"
- );
- }
- "thiscall-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "thiscall-unwind ABI is experimental and subject to change"
- );
- }
- "cdecl-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "cdecl-unwind ABI is experimental and subject to change"
- );
- }
- "fastcall-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "fastcall-unwind ABI is experimental and subject to change"
- );
- }
- "vectorcall-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "vectorcall-unwind ABI is experimental and subject to change"
- );
- }
- "aapcs-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "aapcs-unwind ABI is experimental and subject to change"
- );
- }
- "win64-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "win64-unwind ABI is experimental and subject to change"
- );
- }
- "sysv64-unwind" => {
- gate_feature_post!(
- &self,
- c_unwind,
- span,
- "sysv64-unwind ABI is experimental and subject to change"
- );
- }
- "wasm" => {
- gate_feature_post!(
- &self,
- wasm_abi,
- span,
- "wasm ABI is experimental and subject to change"
- );
+ GateIssue::Language,
+ explain,
+ )
+ .emit();
}
- abi => {
+ Err(abi::AbiDisabled::Unrecognized) => {
if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) {
self.sess.parse_sess.span_diagnostic.delay_span_bug(
span,
- &format!("unrecognized ABI not caught in lowering: {}", abi),
+ &format!(
+ "unrecognized ABI not caught in lowering: {}",
+ symbol_unescaped.as_str()
+ ),
);
}
}
@@ -300,46 +116,6 @@ impl<'a> PostExpansionVisitor<'a> {
}
}
- fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) {
- let has_fields = variants.iter().any(|variant| match variant.data {
- VariantData::Tuple(..) | VariantData::Struct(..) => true,
- VariantData::Unit(..) => false,
- });
-
- let discriminant_spans = variants
- .iter()
- .filter(|variant| match variant.data {
- VariantData::Tuple(..) | VariantData::Struct(..) => false,
- VariantData::Unit(..) => true,
- })
- .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span))
- .collect::<Vec<_>>();
-
- if !discriminant_spans.is_empty() && has_fields {
- let mut err = feature_err(
- &self.sess.parse_sess,
- sym::arbitrary_enum_discriminant,
- discriminant_spans.clone(),
- "custom discriminant values are not allowed in enums with tuple or struct variants",
- );
- for sp in discriminant_spans {
- err.span_label(sp, "disallowed custom discriminant");
- }
- for variant in variants.iter() {
- match &variant.data {
- VariantData::Struct(..) => {
- err.span_label(variant.span, "struct variant defined here");
- }
- VariantData::Tuple(..) => {
- err.span_label(variant.span, "tuple variant defined here");
- }
- VariantData::Unit(..) => {}
- }
- }
- err.emit();
- }
- }
-
/// Feature gate `impl Trait` inside `type Alias = $type_expr;`.
fn check_impl_trait(&self, ty: &ast::Ty) {
struct ImplTraitVisitor<'a> {
@@ -457,26 +233,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
}
- ast::ItemKind::Enum(ast::EnumDef { ref variants, .. }, ..) => {
- for variant in variants {
- match (&variant.data, &variant.disr_expr) {
- (ast::VariantData::Unit(..), _) => {}
- (_, Some(disr_expr)) => gate_feature_post!(
- &self,
- arbitrary_enum_discriminant,
- disr_expr.value.span,
- "discriminants on non-unit variants are experimental"
- ),
- _ => {}
- }
- }
-
- let has_feature = self.features.arbitrary_enum_discriminant;
- if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) {
- self.maybe_report_invalid_custom_discriminants(&variants);
- }
- }
-
ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, ref of_trait, .. }) => {
if let ast::ImplPolarity::Negative(span) = polarity {
gate_feature_post!(
@@ -645,7 +401,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
if let PatKind::Range(Some(_), None, Spanned { .. }) = inner_pat.kind {
gate_feature_post!(
&self,
- half_open_range_patterns,
+ half_open_range_patterns_in_slices,
pat.span,
"`X..` patterns in slices are experimental"
);
@@ -701,7 +457,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
let is_fn = match i.kind {
ast::AssocItemKind::Fn(_) => true,
- ast::AssocItemKind::TyAlias(box ast::TyAlias { ref ty, .. }) => {
+ ast::AssocItemKind::Type(box ast::TyAlias { ref ty, .. }) => {
if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) {
gate_feature_post!(
&self,
@@ -773,7 +529,10 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(generators, "yield syntax is experimental");
gate_all!(raw_ref_op, "raw address of syntax is experimental");
gate_all!(const_trait_impl, "const trait impls are experimental");
- gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
+ gate_all!(
+ half_open_range_patterns_in_slices,
+ "half-open range patterns in slices are unstable"
+ );
gate_all!(inline_const, "inline-const is experimental");
gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
gate_all!(associated_const_equality, "associated const equality is incomplete");
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index 8aa9d57f0..f58fffc91 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -9,7 +9,6 @@
#![feature(if_let_guard)]
#![feature(iter_is_partitioned)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![recursion_limit = "256"]
#[macro_use]
diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml
index 5ad8714e9..a3e3e823b 100644
--- a/compiler/rustc_ast_pretty/Cargo.toml
+++ b/compiler/rustc_ast_pretty/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index ead38caee..bcefa8ce0 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -193,9 +193,13 @@ impl<'a> State<'a> {
self.print_call_post(args)
}
- fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
- let base_args = &args[1..];
- self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
+ fn print_expr_method_call(
+ &mut self,
+ segment: &ast::PathSegment,
+ receiver: &ast::Expr,
+ base_args: &[P<ast::Expr>],
+ ) {
+ self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX);
self.word(".");
self.print_ident(segment.ident);
if let Some(ref args) = segment.args {
@@ -303,8 +307,8 @@ impl<'a> State<'a> {
ast::ExprKind::Call(ref func, ref args) => {
self.print_expr_call(func, &args);
}
- ast::ExprKind::MethodCall(ref segment, ref args, _) => {
- self.print_expr_method_call(segment, &args);
+ ast::ExprKind::MethodCall(ref segment, ref receiver, ref args, _) => {
+ self.print_expr_method_call(segment, &receiver, &args);
}
ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
self.print_expr_binary(op, lhs, rhs);
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 54bac29a6..159853c9e 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -516,7 +516,7 @@ impl<'a> State<'a> {
ast::AssocItemKind::Const(def, ty, body) => {
self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
}
- ast::AssocItemKind::TyAlias(box ast::TyAlias {
+ ast::AssocItemKind::Type(box ast::TyAlias {
defaultness,
generics,
where_clauses,
diff --git a/compiler/rustc_attr/Cargo.toml b/compiler/rustc_attr/Cargo.toml
index ba310a686..6349ddf31 100644
--- a/compiler/rustc_attr/Cargo.toml
+++ b/compiler/rustc_attr/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs
index 52e65a9c7..4580ffcc6 100644
--- a/compiler/rustc_attr/src/lib.rs
+++ b/compiler/rustc_attr/src/lib.rs
@@ -5,7 +5,6 @@
//! to this crate.
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs
index 085175d4b..edccfa1c8 100644
--- a/compiler/rustc_attr/src/session_diagnostics.rs
+++ b/compiler/rustc_attr/src/session_diagnostics.rs
@@ -2,23 +2,22 @@ use std::num::IntErrorKind;
use rustc_ast as ast;
use rustc_errors::{
- error_code, fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler,
+ error_code, fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
};
-use rustc_macros::SessionDiagnostic;
-use rustc_session::SessionDiagnostic;
+use rustc_macros::Diagnostic;
use rustc_span::{Span, Symbol};
use crate::UnsupportedLiteralReason;
-#[derive(SessionDiagnostic)]
-#[diag(attr::expected_one_cfg_pattern, code = "E0536")]
+#[derive(Diagnostic)]
+#[diag(attr_expected_one_cfg_pattern, code = "E0536")]
pub(crate) struct ExpectedOneCfgPattern {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::invalid_predicate, code = "E0537")]
+#[derive(Diagnostic)]
+#[diag(attr_invalid_predicate, code = "E0537")]
pub(crate) struct InvalidPredicate {
#[primary_span]
pub span: Span,
@@ -26,8 +25,8 @@ pub(crate) struct InvalidPredicate {
pub predicate: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::multiple_item, code = "E0538")]
+#[derive(Diagnostic)]
+#[diag(attr_multiple_item, code = "E0538")]
pub(crate) struct MultipleItem {
#[primary_span]
pub span: Span,
@@ -35,8 +34,8 @@ pub(crate) struct MultipleItem {
pub item: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::incorrect_meta_item, code = "E0539")]
+#[derive(Diagnostic)]
+#[diag(attr_incorrect_meta_item, code = "E0539")]
pub(crate) struct IncorrectMetaItem {
#[primary_span]
pub span: Span,
@@ -50,44 +49,44 @@ pub(crate) struct UnknownMetaItem<'a> {
}
// Manual implementation to be able to format `expected` items correctly.
-impl<'a> SessionDiagnostic<'a> for UnknownMetaItem<'_> {
+impl<'a> IntoDiagnostic<'a> for UnknownMetaItem<'_> {
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let expected = self.expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
let mut diag = handler.struct_span_err_with_code(
self.span,
- fluent::attr::unknown_meta_item,
+ fluent::attr_unknown_meta_item,
error_code!(E0541),
);
diag.set_arg("item", self.item);
diag.set_arg("expected", expected.join(", "));
- diag.span_label(self.span, fluent::attr::label);
+ diag.span_label(self.span, fluent::label);
diag
}
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::missing_since, code = "E0542")]
+#[derive(Diagnostic)]
+#[diag(attr_missing_since, code = "E0542")]
pub(crate) struct MissingSince {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::missing_note, code = "E0543")]
+#[derive(Diagnostic)]
+#[diag(attr_missing_note, code = "E0543")]
pub(crate) struct MissingNote {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::multiple_stability_levels, code = "E0544")]
+#[derive(Diagnostic)]
+#[diag(attr_multiple_stability_levels, code = "E0544")]
pub(crate) struct MultipleStabilityLevels {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::invalid_issue_string, code = "E0545")]
+#[derive(Diagnostic)]
+#[diag(attr_invalid_issue_string, code = "E0545")]
pub(crate) struct InvalidIssueString {
#[primary_span]
pub span: Span,
@@ -98,33 +97,33 @@ pub(crate) struct InvalidIssueString {
// The error kinds of `IntErrorKind` are duplicated here in order to allow the messages to be
// translatable.
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub(crate) enum InvalidIssueStringCause {
- #[label(attr::must_not_be_zero)]
+ #[label(must_not_be_zero)]
MustNotBeZero {
#[primary_span]
span: Span,
},
- #[label(attr::empty)]
+ #[label(empty)]
Empty {
#[primary_span]
span: Span,
},
- #[label(attr::invalid_digit)]
+ #[label(invalid_digit)]
InvalidDigit {
#[primary_span]
span: Span,
},
- #[label(attr::pos_overflow)]
+ #[label(pos_overflow)]
PosOverflow {
#[primary_span]
span: Span,
},
- #[label(attr::neg_overflow)]
+ #[label(neg_overflow)]
NegOverflow {
#[primary_span]
span: Span,
@@ -144,22 +143,22 @@ impl InvalidIssueStringCause {
}
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::missing_feature, code = "E0546")]
+#[derive(Diagnostic)]
+#[diag(attr_missing_feature, code = "E0546")]
pub(crate) struct MissingFeature {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::non_ident_feature, code = "E0546")]
+#[derive(Diagnostic)]
+#[diag(attr_non_ident_feature, code = "E0546")]
pub(crate) struct NonIdentFeature {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::missing_issue, code = "E0547")]
+#[derive(Diagnostic)]
+#[diag(attr_missing_issue, code = "E0547")]
pub(crate) struct MissingIssue {
#[primary_span]
pub span: Span,
@@ -167,8 +166,8 @@ pub(crate) struct MissingIssue {
// FIXME: This diagnostic is identical to `IncorrectMetaItem`, barring the error code. Consider
// changing this to `IncorrectMetaItem`. See #51489.
-#[derive(SessionDiagnostic)]
-#[diag(attr::incorrect_meta_item, code = "E0551")]
+#[derive(Diagnostic)]
+#[diag(attr_incorrect_meta_item, code = "E0551")]
pub(crate) struct IncorrectMetaItem2 {
#[primary_span]
pub span: Span,
@@ -176,15 +175,15 @@ pub(crate) struct IncorrectMetaItem2 {
// FIXME: Why is this the same error code as `InvalidReprHintNoParen` and `InvalidReprHintNoValue`?
// It is more similar to `IncorrectReprFormatGeneric`.
-#[derive(SessionDiagnostic)]
-#[diag(attr::incorrect_repr_format_packed_one_or_zero_arg, code = "E0552")]
+#[derive(Diagnostic)]
+#[diag(attr_incorrect_repr_format_packed_one_or_zero_arg, code = "E0552")]
pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::invalid_repr_hint_no_paren, code = "E0552")]
+#[derive(Diagnostic)]
+#[diag(attr_invalid_repr_hint_no_paren, code = "E0552")]
pub(crate) struct InvalidReprHintNoParen {
#[primary_span]
pub span: Span,
@@ -192,8 +191,8 @@ pub(crate) struct InvalidReprHintNoParen {
pub name: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::invalid_repr_hint_no_value, code = "E0552")]
+#[derive(Diagnostic)]
+#[diag(attr_invalid_repr_hint_no_value, code = "E0552")]
pub(crate) struct InvalidReprHintNoValue {
#[primary_span]
pub span: Span,
@@ -209,18 +208,18 @@ pub(crate) struct UnsupportedLiteral {
pub start_point_span: Span,
}
-impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral {
+impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral {
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut diag = handler.struct_span_err_with_code(
self.span,
match self.reason {
- UnsupportedLiteralReason::Generic => fluent::attr::unsupported_literal_generic,
- UnsupportedLiteralReason::CfgString => fluent::attr::unsupported_literal_cfg_string,
+ UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic,
+ UnsupportedLiteralReason::CfgString => fluent::attr_unsupported_literal_cfg_string,
UnsupportedLiteralReason::DeprecatedString => {
- fluent::attr::unsupported_literal_deprecated_string
+ fluent::attr_unsupported_literal_deprecated_string
}
UnsupportedLiteralReason::DeprecatedKvPair => {
- fluent::attr::unsupported_literal_deprecated_kv_pair
+ fluent::attr_unsupported_literal_deprecated_kv_pair
}
},
error_code!(E0565),
@@ -228,7 +227,7 @@ impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral {
if self.is_bytestr {
diag.span_suggestion(
self.start_point_span,
- fluent::attr::unsupported_literal_suggestion,
+ fluent::attr_unsupported_literal_suggestion,
"",
Applicability::MaybeIncorrect,
);
@@ -237,16 +236,16 @@ impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral {
}
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::invalid_repr_align_need_arg, code = "E0589")]
+#[derive(Diagnostic)]
+#[diag(attr_invalid_repr_align_need_arg, code = "E0589")]
pub(crate) struct InvalidReprAlignNeedArg {
#[primary_span]
#[suggestion(code = "align(...)", applicability = "has-placeholders")]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::invalid_repr_generic, code = "E0589")]
+#[derive(Diagnostic)]
+#[diag(attr_invalid_repr_generic, code = "E0589")]
pub(crate) struct InvalidReprGeneric<'a> {
#[primary_span]
pub span: Span,
@@ -255,15 +254,15 @@ pub(crate) struct InvalidReprGeneric<'a> {
pub error_part: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::incorrect_repr_format_align_one_arg, code = "E0693")]
+#[derive(Diagnostic)]
+#[diag(attr_incorrect_repr_format_align_one_arg, code = "E0693")]
pub(crate) struct IncorrectReprFormatAlignOneArg {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::incorrect_repr_format_generic, code = "E0693")]
+#[derive(Diagnostic)]
+#[diag(attr_incorrect_repr_format_generic, code = "E0693")]
pub(crate) struct IncorrectReprFormatGeneric<'a> {
#[primary_span]
pub span: Span,
@@ -274,9 +273,9 @@ pub(crate) struct IncorrectReprFormatGeneric<'a> {
pub cause: Option<IncorrectReprFormatGenericCause<'a>>,
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub(crate) enum IncorrectReprFormatGenericCause<'a> {
- #[suggestion(attr::suggestion, code = "{name}({int})", applicability = "machine-applicable")]
+ #[suggestion(suggestion, code = "{name}({int})", applicability = "machine-applicable")]
Int {
#[primary_span]
span: Span,
@@ -288,11 +287,7 @@ pub(crate) enum IncorrectReprFormatGenericCause<'a> {
int: u128,
},
- #[suggestion(
- attr::suggestion,
- code = "{name}({symbol})",
- applicability = "machine-applicable"
- )]
+ #[suggestion(suggestion, code = "{name}({symbol})", applicability = "machine-applicable")]
Symbol {
#[primary_span]
span: Span,
@@ -317,29 +312,29 @@ impl<'a> IncorrectReprFormatGenericCause<'a> {
}
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::rustc_promotable_pairing, code = "E0717")]
+#[derive(Diagnostic)]
+#[diag(attr_rustc_promotable_pairing, code = "E0717")]
pub(crate) struct RustcPromotablePairing {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::rustc_allowed_unstable_pairing, code = "E0789")]
+#[derive(Diagnostic)]
+#[diag(attr_rustc_allowed_unstable_pairing, code = "E0789")]
pub(crate) struct RustcAllowedUnstablePairing {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::cfg_predicate_identifier)]
+#[derive(Diagnostic)]
+#[diag(attr_cfg_predicate_identifier)]
pub(crate) struct CfgPredicateIdentifier {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::deprecated_item_suggestion)]
+#[derive(Diagnostic)]
+#[diag(attr_deprecated_item_suggestion)]
pub(crate) struct DeprecatedItemSuggestion {
#[primary_span]
pub span: Span,
@@ -351,22 +346,22 @@ pub(crate) struct DeprecatedItemSuggestion {
pub details: (),
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::expected_single_version_literal)]
+#[derive(Diagnostic)]
+#[diag(attr_expected_single_version_literal)]
pub(crate) struct ExpectedSingleVersionLiteral {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::expected_version_literal)]
+#[derive(Diagnostic)]
+#[diag(attr_expected_version_literal)]
pub(crate) struct ExpectedVersionLiteral {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::expects_feature_list)]
+#[derive(Diagnostic)]
+#[diag(attr_expects_feature_list)]
pub(crate) struct ExpectsFeatureList {
#[primary_span]
pub span: Span,
@@ -374,8 +369,8 @@ pub(crate) struct ExpectsFeatureList {
pub name: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::expects_features)]
+#[derive(Diagnostic)]
+#[diag(attr_expects_features)]
pub(crate) struct ExpectsFeatures {
#[primary_span]
pub span: Span,
@@ -383,15 +378,15 @@ pub(crate) struct ExpectsFeatures {
pub name: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::soft_no_args)]
+#[derive(Diagnostic)]
+#[diag(attr_soft_no_args)]
pub(crate) struct SoftNoArgs {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(attr::unknown_version_literal)]
+#[derive(Diagnostic)]
+#[diag(attr_unknown_version_literal)]
pub(crate) struct UnknownVersionLiteral {
#[primary_span]
pub span: Span,
diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml
index fbf628e86..87c113f3e 100644
--- a/compiler/rustc_borrowck/Cargo.toml
+++ b/compiler/rustc_borrowck/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
either = "1.5.0"
diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs
index 144fd15fc..f185e402f 100644
--- a/compiler/rustc_borrowck/src/constraint_generation.rs
+++ b/compiler/rustc_borrowck/src/constraint_generation.rs
@@ -14,8 +14,8 @@ use crate::{
places_conflict, region_infer::values::LivenessValues,
};
-pub(super) fn generate_constraints<'cx, 'tcx>(
- infcx: &InferCtxt<'cx, 'tcx>,
+pub(super) fn generate_constraints<'tcx>(
+ infcx: &InferCtxt<'tcx>,
liveness_constraints: &mut LivenessValues<RegionVid>,
all_facts: &mut Option<AllFacts>,
location_table: &LocationTable,
@@ -37,8 +37,8 @@ pub(super) fn generate_constraints<'cx, 'tcx>(
}
/// 'cg = the duration of the constraint generation process itself.
-struct ConstraintGeneration<'cg, 'cx, 'tcx> {
- infcx: &'cg InferCtxt<'cx, 'tcx>,
+struct ConstraintGeneration<'cg, 'tcx> {
+ infcx: &'cg InferCtxt<'tcx>,
all_facts: &'cg mut Option<AllFacts>,
location_table: &'cg LocationTable,
liveness_constraints: &'cg mut LivenessValues<RegionVid>,
@@ -46,7 +46,7 @@ struct ConstraintGeneration<'cg, 'cx, 'tcx> {
body: &'cg Body<'tcx>,
}
-impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> {
+impl<'cg, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'tcx> {
fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) {
self.super_basic_block_data(bb, data);
}
@@ -156,7 +156,7 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> {
}
}
-impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
+impl<'cx, 'tcx> ConstraintGeneration<'cx, 'tcx> {
/// Some variable with type `live_ty` is "regular live" at
/// `location` -- i.e., it may be used later. This means that all
/// regions appearing in the type `live_ty` must be live at
diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs
index efc17a173..b162095f8 100644
--- a/compiler/rustc_borrowck/src/consumers.rs
+++ b/compiler/rustc_borrowck/src/consumers.rs
@@ -31,9 +31,8 @@ pub fn get_body_with_borrowck_facts<'tcx>(
def: ty::WithOptConstParam<LocalDefId>,
) -> BodyWithBorrowckFacts<'tcx> {
let (input_body, promoted) = tcx.mir_promoted(def);
- tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).enter(|infcx| {
- let input_body: &Body<'_> = &input_body.borrow();
- let promoted: &IndexVec<_, _> = &promoted.borrow();
- *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap()
- })
+ let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).build();
+ let input_body: &Body<'_> = &input_body.borrow();
+ let promoted: &IndexVec<_, _> = &promoted.borrow();
+ *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap()
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index b1def1892..02071ed6b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -56,7 +56,7 @@ impl<'tcx> UniverseInfo<'tcx> {
) {
match self.0 {
UniverseInfoInner::RelateTys { expected, found } => {
- let err = mbcx.infcx.report_mismatched_types(
+ let err = mbcx.infcx.err_ctxt().report_mismatched_types(
&cause,
expected,
found,
@@ -238,20 +238,11 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
- mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
- cause.span,
- &self.canonical_query,
- |ref infcx, key, _| {
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
- type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
- try_extract_error_from_fulfill_cx(
- fulfill_cx,
- infcx,
- placeholder_region,
- error_region,
- )
- },
- )
+ let (ref infcx, key, _) =
+ mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+ type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
+ try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
}
}
@@ -288,37 +279,24 @@ where
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
- mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
- cause.span,
- &self.canonical_query,
- |ref infcx, key, _| {
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
- let mut selcx = SelectionContext::new(infcx);
-
- // FIXME(lqd): Unify and de-duplicate the following with the actual
- // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
- // `ObligationCause`. The normalization results are currently different between
- // `AtExt::normalize` used in the query and `normalize` called below: the former fails
- // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
- // after #85499 lands to see if its fixes have erased this difference.
- let (param_env, value) = key.into_parts();
- let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
- &mut selcx,
- param_env,
- cause,
- value.value,
- );
- fulfill_cx.register_predicate_obligations(infcx, obligations);
-
- try_extract_error_from_fulfill_cx(
- fulfill_cx,
- infcx,
- placeholder_region,
- error_region,
- )
- },
- )
+ let (ref infcx, key, _) =
+ mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+
+ let mut selcx = SelectionContext::new(infcx);
+
+ // FIXME(lqd): Unify and de-duplicate the following with the actual
+ // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
+ // `ObligationCause`. The normalization results are currently different between
+ // `AtExt::normalize` used in the query and `normalize` called below: the former fails
+ // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
+ // after #85499 lands to see if its fixes have erased this difference.
+ let (param_env, value) = key.into_parts();
+ let Normalized { value: _, obligations } =
+ rustc_trait_selection::traits::normalize(&mut selcx, param_env, cause, value.value);
+ fulfill_cx.register_predicate_obligations(infcx, obligations);
+
+ try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
}
}
@@ -349,21 +327,11 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
- mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
- cause.span,
- &self.canonical_query,
- |ref infcx, key, _| {
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
- type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
- .ok()?;
- try_extract_error_from_fulfill_cx(
- fulfill_cx,
- infcx,
- placeholder_region,
- error_region,
- )
- },
- )
+ let (ref infcx, key, _) =
+ mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+ type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)).ok()?;
+ try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
}
}
@@ -407,7 +375,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
#[instrument(skip(fulfill_cx, infcx), level = "debug")]
fn try_extract_error_from_fulfill_cx<'tcx>(
mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
@@ -427,7 +395,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
}
fn try_extract_error_from_region_constraints<'tcx>(
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
region_constraints: &RegionConstraintData<'tcx>,
@@ -449,42 +417,38 @@ fn try_extract_error_from_region_constraints<'tcx>(
})?;
debug!(?sub_region, "cause = {:#?}", cause);
- let nice_error = match (error_region, *sub_region) {
- (Some(error_region), ty::ReVar(vid)) => NiceRegionError::new(
- infcx,
- RegionResolutionError::SubSupConflict(
- vid,
- region_var_origin(vid),
- cause.clone(),
- error_region,
- cause.clone(),
- placeholder_region,
- vec![],
- ),
- ),
- (Some(error_region), _) => NiceRegionError::new(
- infcx,
- RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
+ let error = match (error_region, *sub_region) {
+ (Some(error_region), ty::ReVar(vid)) => RegionResolutionError::SubSupConflict(
+ vid,
+ region_var_origin(vid),
+ cause.clone(),
+ error_region,
+ cause.clone(),
+ placeholder_region,
+ vec![],
),
+ (Some(error_region), _) => {
+ RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region)
+ }
// Note universe here is wrong...
- (None, ty::ReVar(vid)) => NiceRegionError::new(
- infcx,
- RegionResolutionError::UpperBoundUniverseConflict(
- vid,
- region_var_origin(vid),
- universe_of_region(vid),
- cause.clone(),
- placeholder_region,
- ),
- ),
- (None, _) => NiceRegionError::new(
- infcx,
- RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region),
+ (None, ty::ReVar(vid)) => RegionResolutionError::UpperBoundUniverseConflict(
+ vid,
+ region_var_origin(vid),
+ universe_of_region(vid),
+ cause.clone(),
+ placeholder_region,
),
+ (None, _) => {
+ RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region)
+ }
};
- nice_error.try_report_from_nll().or_else(|| {
+ NiceRegionError::new(&infcx.err_ctxt(), error).try_report_from_nll().or_else(|| {
if let SubregionOrigin::Subtype(trace) = cause {
- Some(infcx.report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch))
+ Some(
+ infcx
+ .err_ctxt()
+ .report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch),
+ )
} else {
None
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index f2204c242..583bc2e28 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -16,7 +16,7 @@ use rustc_middle::mir::{
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
};
-use rustc_middle::ty::{self, subst::Subst, suggest_constraining_type_params, PredicateKind, Ty};
+use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty};
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
@@ -198,7 +198,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
move_span,
move_spans,
*moved_place,
- Some(used_place),
partially_str,
loop_message,
move_msg,
@@ -369,6 +368,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut visitor = ConditionVisitor { spans: &spans, name: &name, errors: vec![] };
visitor.visit_body(&body);
+ let mut show_assign_sugg = false;
let isnt_initialized = if let InitializationRequiringAction::PartialAssignment
| InitializationRequiringAction::Assignment = desired_action
{
@@ -396,6 +396,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.count()
== 0
{
+ show_assign_sugg = true;
"isn't initialized"
} else {
"is possibly-uninitialized"
@@ -446,10 +447,84 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
}
+
err.span_label(decl_span, "binding declared here but left uninitialized");
+ if show_assign_sugg {
+ struct LetVisitor {
+ decl_span: Span,
+ sugg_span: Option<Span>,
+ }
+
+ impl<'v> Visitor<'v> for LetVisitor {
+ fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
+ if self.sugg_span.is_some() {
+ return;
+ }
+ if let hir::StmtKind::Local(hir::Local {
+ span, ty, init: None, ..
+ }) = &ex.kind && span.contains(self.decl_span) {
+ self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span));
+ }
+ hir::intravisit::walk_stmt(self, ex);
+ }
+ }
+
+ let mut visitor = LetVisitor { decl_span, sugg_span: None };
+ visitor.visit_body(&body);
+ if let Some(span) = visitor.sugg_span {
+ self.suggest_assign_value(&mut err, moved_place, span);
+ }
+ }
err
}
+ fn suggest_assign_value(
+ &self,
+ err: &mut Diagnostic,
+ moved_place: PlaceRef<'tcx>,
+ sugg_span: Span,
+ ) {
+ let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
+ debug!("ty: {:?}, kind: {:?}", ty, ty.kind());
+
+ let tcx = self.infcx.tcx;
+ let implements_default = |ty, param_env| {
+ 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),
+ ty::List::empty(),
+ param_env,
+ )
+ .must_apply_modulo_regions()
+ };
+
+ let assign_value = match ty.kind() {
+ ty::Bool => "false",
+ ty::Float(_) => "0.0",
+ ty::Int(_) | ty::Uint(_) => "0",
+ ty::Never | ty::Error(_) => "",
+ ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => "vec![]",
+ ty::Adt(_, _) if implements_default(ty, self.param_env) => "Default::default()",
+ _ => "todo!()",
+ };
+
+ if !assign_value.is_empty() {
+ err.span_suggestion_verbose(
+ sugg_span.shrink_to_hi(),
+ format!("consider assigning a value"),
+ format!(" = {}", assign_value),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+
fn suggest_borrow_fn_like(
&self,
err: &mut Diagnostic,
@@ -537,41 +612,40 @@ 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 predicates: Result<Vec<_>, _> = tcx.infer_ctxt().enter(|infcx| {
- let mut fulfill_cx = <dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx);
+ let infcx = tcx.infer_ctxt().build();
+ let mut fulfill_cx = <dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx);
- let copy_did = infcx.tcx.lang_items().copy_trait().unwrap();
- let cause = ObligationCause::new(
- span,
- self.mir_hir_id(),
- rustc_infer::traits::ObligationCauseCode::MiscObligation,
- );
- fulfill_cx.register_bound(
- &infcx,
- self.param_env,
- // Erase any region vids from the type, which may not be resolved
- infcx.tcx.erase_regions(ty),
- copy_did,
- cause,
- );
- // Select all, including ambiguous predicates
- let errors = fulfill_cx.select_all_or_error(&infcx);
-
- // Only emit suggestion if all required predicates are on generic
- errors
- .into_iter()
- .map(|err| match err.obligation.predicate.kind().skip_binder() {
- PredicateKind::Trait(predicate) => match predicate.self_ty().kind() {
- ty::Param(param_ty) => Ok((
- generics.type_param(param_ty, tcx),
- predicate.trait_ref.print_only_trait_path().to_string(),
- )),
- _ => Err(()),
- },
+ let copy_did = infcx.tcx.lang_items().copy_trait().unwrap();
+ let cause = ObligationCause::new(
+ span,
+ self.mir_hir_id(),
+ rustc_infer::traits::ObligationCauseCode::MiscObligation,
+ );
+ fulfill_cx.register_bound(
+ &infcx,
+ self.param_env,
+ // Erase any region vids from the type, which may not be resolved
+ infcx.tcx.erase_regions(ty),
+ copy_did,
+ cause,
+ );
+ // Select all, including ambiguous predicates
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+
+ // Only emit suggestion if all required predicates are on generic
+ let predicates: Result<Vec<_>, _> = errors
+ .into_iter()
+ .map(|err| match err.obligation.predicate.kind().skip_binder() {
+ PredicateKind::Trait(predicate) => match predicate.self_ty().kind() {
+ ty::Param(param_ty) => Ok((
+ generics.type_param(param_ty, tcx),
+ predicate.trait_ref.print_only_trait_path().to_string(),
+ )),
_ => Err(()),
- })
- .collect()
- });
+ },
+ _ => Err(()),
+ })
+ .collect();
if let Ok(predicates) = predicates {
suggest_constraining_type_params(
@@ -2146,7 +2220,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
StorageDeadOrDrop::Destructor(_) => kind,
},
- ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
+ ProjectionElem::OpaqueCast { .. }
+ | ProjectionElem::Field(..)
+ | ProjectionElem::Downcast(..) => {
match place_ty.ty.kind() {
ty::Adt(def, _) if def.has_dtor(tcx) => {
// Report the outermost adt with a destructor
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 1c01e78ab..582d683dd 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -1,8 +1,5 @@
//! Print diagnostics to explain why values are borrowed.
-use std::collections::VecDeque;
-
-use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diagnostic};
use rustc_index::vec::IndexVec;
use rustc_infer::infer::NllRegionVariableOrigin;
@@ -359,19 +356,37 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let borrow_region_vid = borrow.region;
debug!(?borrow_region_vid);
- let region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location);
+ let mut region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location);
debug!(?region_sub);
- match find_use::find(body, regioncx, tcx, region_sub, location) {
+ let mut use_location = location;
+ let mut use_in_later_iteration_of_loop = false;
+
+ if region_sub == borrow_region_vid {
+ // When `region_sub` is the same as `borrow_region_vid` (the location where the borrow is
+ // issued is the same location that invalidates the reference), this is likely a loop iteration
+ // - in this case, try using the loop terminator location in `find_sub_region_live_at`.
+ if let Some(loop_terminator_location) =
+ regioncx.find_loop_terminator_location(borrow.region, body)
+ {
+ region_sub = self
+ .regioncx
+ .find_sub_region_live_at(borrow_region_vid, loop_terminator_location);
+ debug!("explain_why_borrow_contains_point: region_sub in loop={:?}", region_sub);
+ use_location = loop_terminator_location;
+ use_in_later_iteration_of_loop = true;
+ }
+ }
+
+ match find_use::find(body, regioncx, tcx, region_sub, use_location) {
Some(Cause::LiveVar(local, location)) => {
let span = body.source_info(location).span;
let spans = self
.move_spans(Place::from(local).as_ref(), location)
.or_else(|| self.borrow_spans(span, location));
- let borrow_location = location;
- if self.is_use_in_later_iteration_of_loop(borrow_location, location) {
- let later_use = self.later_use_kind(borrow, spans, location);
+ if use_in_later_iteration_of_loop {
+ let later_use = self.later_use_kind(borrow, spans, use_location);
BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2)
} else {
// Check if the location represents a `FakeRead`, and adapt the error
@@ -425,131 +440,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
- /// true if `borrow_location` can reach `use_location` by going through a loop and
- /// `use_location` is also inside of that loop
- fn is_use_in_later_iteration_of_loop(
- &self,
- borrow_location: Location,
- use_location: Location,
- ) -> bool {
- let back_edge = self.reach_through_backedge(borrow_location, use_location);
- back_edge.map_or(false, |back_edge| self.can_reach_head_of_loop(use_location, back_edge))
- }
-
- /// Returns the outmost back edge if `from` location can reach `to` location passing through
- /// that back edge
- fn reach_through_backedge(&self, from: Location, to: Location) -> Option<Location> {
- let mut visited_locations = FxHashSet::default();
- let mut pending_locations = VecDeque::new();
- visited_locations.insert(from);
- pending_locations.push_back(from);
- debug!("reach_through_backedge: from={:?} to={:?}", from, to,);
-
- let mut outmost_back_edge = None;
- while let Some(location) = pending_locations.pop_front() {
- debug!(
- "reach_through_backedge: location={:?} outmost_back_edge={:?}
- pending_locations={:?} visited_locations={:?}",
- location, outmost_back_edge, pending_locations, visited_locations
- );
-
- if location == to && outmost_back_edge.is_some() {
- // We've managed to reach the use location
- debug!("reach_through_backedge: found!");
- return outmost_back_edge;
- }
-
- let block = &self.body.basic_blocks[location.block];
-
- if location.statement_index < block.statements.len() {
- let successor = location.successor_within_block();
- if visited_locations.insert(successor) {
- pending_locations.push_back(successor);
- }
- } else {
- pending_locations.extend(
- block
- .terminator()
- .successors()
- .map(|bb| Location { statement_index: 0, block: bb })
- .filter(|s| visited_locations.insert(*s))
- .map(|s| {
- if self.is_back_edge(location, s) {
- match outmost_back_edge {
- None => {
- outmost_back_edge = Some(location);
- }
-
- Some(back_edge)
- if location.dominates(back_edge, &self.dominators) =>
- {
- outmost_back_edge = Some(location);
- }
-
- Some(_) => {}
- }
- }
-
- s
- }),
- );
- }
- }
-
- None
- }
-
- /// true if `from` location can reach `loop_head` location and `loop_head` dominates all the
- /// intermediate nodes
- fn can_reach_head_of_loop(&self, from: Location, loop_head: Location) -> bool {
- self.find_loop_head_dfs(from, loop_head, &mut FxHashSet::default())
- }
-
- fn find_loop_head_dfs(
- &self,
- from: Location,
- loop_head: Location,
- visited_locations: &mut FxHashSet<Location>,
- ) -> bool {
- visited_locations.insert(from);
-
- if from == loop_head {
- return true;
- }
-
- if loop_head.dominates(from, &self.dominators) {
- let block = &self.body.basic_blocks[from.block];
-
- if from.statement_index < block.statements.len() {
- let successor = from.successor_within_block();
-
- if !visited_locations.contains(&successor)
- && self.find_loop_head_dfs(successor, loop_head, visited_locations)
- {
- return true;
- }
- } else {
- for bb in block.terminator().successors() {
- let successor = Location { statement_index: 0, block: bb };
-
- if !visited_locations.contains(&successor)
- && self.find_loop_head_dfs(successor, loop_head, visited_locations)
- {
- return true;
- }
- }
- }
- }
-
- false
- }
-
- /// True if an edge `source -> target` is a backedge -- in other words, if the target
- /// dominates the source.
- fn is_back_edge(&self, source: Location, target: Location) -> bool {
- target.dominates(source, &self.dominators)
- }
-
/// Determine how the borrow was later used.
/// First span returned points to the location of the conflicting use
/// Second span if `Some` is returned in the case of closures and points
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 683084cf0..534d9ecae 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -237,6 +237,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
ProjectionElem::Downcast(..) if opt.including_downcast => return None,
ProjectionElem::Downcast(..) => (),
+ ProjectionElem::OpaqueCast(..) => (),
ProjectionElem::Field(field, _ty) => {
// FIXME(project-rfc_2229#36): print capture precisely here.
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
@@ -317,6 +318,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
}
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
+ ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty),
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
},
};
@@ -970,7 +972,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
move_span: Span,
move_spans: UseSpans<'tcx>,
moved_place: Place<'tcx>,
- used_place: Option<PlaceRef<'tcx>>,
partially_str: &str,
loop_message: &str,
move_msg: &str,
@@ -1024,7 +1025,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
- Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
+ Some(def_id) => {
+ let infcx = self.infcx.tcx.infer_ctxt().build();
type_known_to_meet_bound_modulo_regions(
&infcx,
self.param_env,
@@ -1035,7 +1037,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
def_id,
DUMMY_SP,
)
- }),
+ }
_ => false,
};
if suggest {
@@ -1058,9 +1060,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
place_name, partially_str, loop_message
),
);
- // If we have a `&mut` ref, we need to reborrow.
- if let Some(ty::Ref(_, _, hir::Mutability::Mut)) = used_place
- .map(|used_place| used_place.ty(self.body, self.infcx.tcx).ty.kind())
+ // 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.
+ if let ty::Ref(_, _, hir::Mutability::Mut) =
+ moved_place.ty(self.body, self.infcx.tcx).ty.kind()
{
// If we are in a loop this will be suggested later.
if !is_loop_move {
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 8d4c38d3a..5a47f4567 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -401,7 +401,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
};
if let Some(use_spans) = use_spans {
self.explain_captures(
- &mut err, span, span, use_spans, move_place, None, "", "", "", false, true,
+ &mut err, span, span, use_spans, move_place, "", "", "", false, true,
);
}
err
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 6b5014fa9..8ad40c0aa 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -169,6 +169,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
..,
ProjectionElem::Index(_)
| ProjectionElem::ConstantIndex { .. }
+ | ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..),
],
@@ -931,7 +932,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let opt_suggestions = self
.infcx
.tcx
- .typeck(path_segment.hir_id.owner)
+ .typeck(path_segment.hir_id.owner.def_id)
.type_dependent_def_id(*hir_id)
.and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
.map(|def_id| self.infcx.tcx.associated_items(def_id))
@@ -1031,7 +1032,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if look_at_return && hir.get_return_block(closure_id).is_some() {
// ...otherwise we are probably in the tail expression of the function, point at the
// return type.
- match hir.get_by_def_id(hir.get_parent_item(fn_call_id)) {
+ match hir.get_by_def_id(hir.get_parent_item(fn_call_id).def_id) {
hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. })
| hir::Node::TraitItem(hir::TraitItem {
ident,
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 34be2874f..15230718d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -186,7 +186,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let Some(lower_bound_region) = lower_bound_region {
let generic_ty = type_test.generic_kind.to_ty(self.infcx.tcx);
let origin = RelateParamBound(type_test_span, generic_ty, None);
- self.buffer_error(self.infcx.construct_generic_bound_failure(
+ self.buffer_error(self.infcx.err_ctxt().construct_generic_bound_failure(
self.body.source.def_id().expect_local(),
type_test_span,
Some(origin),
@@ -281,7 +281,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let tcx = self.infcx.tcx;
match tcx.hir().get_if_local(def_id) {
Some(Node::ImplItem(impl_item)) => {
- match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id())) {
+ match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
+ {
Some(Node::Item(Item {
kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
..
@@ -291,7 +292,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
Some(Node::TraitItem(trait_item)) => {
let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
- match tcx.hir().find_by_def_id(trait_did) {
+ match tcx.hir().find_by_def_id(trait_did.def_id) {
Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
// The method being called is defined in the `trait`, but the `'static`
// obligation comes from the `impl`. Find that `impl` so that we can point
@@ -340,7 +341,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
/// Report an error because the universal region `fr` was required to outlive
/// `outlived_fr` but it is not known to do so. For example:
///
- /// ```compile_fail,E0312
+ /// ```compile_fail
/// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
/// ```
///
@@ -364,7 +365,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// Check if we can use one of the "nice region errors".
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
- let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f);
+ let infer_err = self.infcx.err_ctxt();
+ let nice = NiceRegionError::new_from_span(&infer_err, cause.span, o, f);
if let Some(diag) = nice.try_report_from_nll() {
self.buffer_error(diag);
return;
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 6c1eaa809..c044dbaba 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -251,7 +251,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
.or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr))
.or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr))
.or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr))
- .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr));
+ .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr))
+ .or_else(|| self.give_name_if_anonymous_region_appears_in_arg_position_impl_trait(fr));
if let Some(ref value) = value {
self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone());
@@ -707,7 +708,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
hir::AsyncGeneratorKind::Block => " of async block",
hir::AsyncGeneratorKind::Closure => " of async closure",
hir::AsyncGeneratorKind::Fn => {
- let parent_item = hir.get_by_def_id(hir.get_parent_item(mir_hir_id));
+ let parent_item =
+ hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
let output = &parent_item
.fn_decl()
.expect("generator lowered from async fn should be in fn")
@@ -863,20 +865,13 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
};
let tcx = self.infcx.tcx;
- let body_parent_did = tcx.opt_parent(self.mir_def_id().to_def_id())?;
- if tcx.parent(region.def_id) != body_parent_did
- || tcx.def_kind(body_parent_did) != DefKind::Impl
- {
+ let region_parent = tcx.parent(region.def_id);
+ if tcx.def_kind(region_parent) != DefKind::Impl {
return None;
}
- let mut found = false;
- tcx.fold_regions(tcx.type_of(body_parent_did), |r: ty::Region<'tcx>, _| {
- if *r == ty::ReEarlyBound(region) {
- found = true;
- }
- r
- });
+ let found = tcx
+ .any_free_region_meets(&tcx.type_of(region_parent), |r| *r == ty::ReEarlyBound(region));
Some(RegionName {
name: self.synthesize_region_name(),
@@ -889,4 +884,92 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
),
})
}
+
+ fn give_name_if_anonymous_region_appears_in_arg_position_impl_trait(
+ &self,
+ fr: RegionVid,
+ ) -> Option<RegionName> {
+ let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else {
+ return None;
+ };
+ if region.has_name() {
+ return None;
+ };
+
+ let predicates = self
+ .infcx
+ .tcx
+ .predicates_of(self.body.source.def_id())
+ .instantiate_identity(self.infcx.tcx)
+ .predicates;
+
+ if let Some(upvar_index) = self
+ .regioncx
+ .universal_regions()
+ .defining_ty
+ .upvar_tys()
+ .position(|ty| self.any_param_predicate_mentions(&predicates, ty, region))
+ {
+ let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
+ self.infcx.tcx,
+ &self.upvars,
+ upvar_index,
+ );
+ let region_name = self.synthesize_region_name();
+
+ Some(RegionName {
+ name: region_name,
+ source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name),
+ })
+ } else if let Some(arg_index) = self
+ .regioncx
+ .universal_regions()
+ .unnormalized_input_tys
+ .iter()
+ .position(|ty| self.any_param_predicate_mentions(&predicates, *ty, region))
+ {
+ let (arg_name, arg_span) = self.regioncx.get_argument_name_and_span_for_region(
+ self.body,
+ &self.local_names,
+ arg_index,
+ );
+ let region_name = self.synthesize_region_name();
+
+ Some(RegionName {
+ name: region_name,
+ source: RegionNameSource::AnonRegionFromArgument(
+ RegionNameHighlight::CannotMatchHirTy(arg_span, arg_name?.to_string()),
+ ),
+ })
+ } else {
+ None
+ }
+ }
+
+ fn any_param_predicate_mentions(
+ &self,
+ predicates: &[ty::Predicate<'tcx>],
+ ty: Ty<'tcx>,
+ region: ty::EarlyBoundRegion,
+ ) -> bool {
+ let tcx = self.infcx.tcx;
+ ty.walk().any(|arg| {
+ if let ty::GenericArgKind::Type(ty) = arg.unpack()
+ && let ty::Param(_) = ty.kind()
+ {
+ predicates.iter().any(|pred| {
+ match pred.kind().skip_binder() {
+ ty::PredicateKind::Trait(data) if data.self_ty() == ty => {}
+ ty::PredicateKind::Projection(data) if data.projection_ty.self_ty() == ty => {}
+ _ => return false,
+ }
+ tcx.any_free_region_meets(pred, |r| {
+ *r == ty::ReEarlyBound(region)
+ })
+ })
+ } else {
+ false
+ }
+ })
+ }
}
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 86da87d06..abfe253d4 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -3,7 +3,6 @@
#![allow(rustc::potential_query_instability)]
#![feature(box_patterns)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(rustc_attrs)]
@@ -132,14 +131,11 @@ fn mir_borrowck<'tcx>(
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
- let opt_closure_req = tcx
- .infer_ctxt()
- .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner))
- .enter(|infcx| {
- let input_body: &Body<'_> = &input_body.borrow();
- let promoted: &IndexVec<_, _> = &promoted.borrow();
- do_mir_borrowck(&infcx, input_body, promoted, false).0
- });
+ 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: &IndexVec<_, _> = &promoted.borrow();
+ let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, false).0;
debug!("mir_borrowck done");
tcx.arena.alloc(opt_closure_req)
@@ -151,8 +147,8 @@ fn mir_borrowck<'tcx>(
/// 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")]
-fn do_mir_borrowck<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+fn do_mir_borrowck<'tcx>(
+ infcx: &InferCtxt<'tcx>,
input_body: &Body<'tcx>,
input_promoted: &IndexVec<Promoted, Body<'tcx>>,
return_body_with_facts: bool,
@@ -475,7 +471,7 @@ pub struct BodyWithBorrowckFacts<'tcx> {
}
struct MirBorrowckCtxt<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
body: &'cx Body<'tcx>,
move_data: &'cx MoveData<'tcx>,
@@ -1781,6 +1777,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
for (place_base, elem) in place.iter_projections().rev() {
match elem {
ProjectionElem::Index(_/*operand*/) |
+ ProjectionElem::OpaqueCast(_) |
ProjectionElem::ConstantIndex { .. } |
// assigning to P[i] requires P to be valid.
ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) =>
@@ -2172,6 +2169,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
+ | ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Downcast(..) => {
let upvar_field_projection = self.is_upvar_field_projection(place);
if let Some(field) = upvar_field_projection {
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 12b2481cc..08fdd28eb 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -55,8 +55,8 @@ pub(crate) struct NllOutput<'tcx> {
/// regions (e.g., region parameters) declared on the function. That set will need to be given to
/// `compute_regions`.
#[instrument(skip(infcx, param_env, body, promoted), level = "debug")]
-pub(crate) fn replace_regions_in_mir<'cx, 'tcx>(
- infcx: &InferCtxt<'cx, 'tcx>,
+pub(crate) fn replace_regions_in_mir<'tcx>(
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &mut Body<'tcx>,
promoted: &mut IndexVec<Promoted, Body<'tcx>>,
@@ -155,7 +155,7 @@ fn populate_polonius_move_facts(
///
/// This may result in errors being reported.
pub(crate) fn compute_regions<'cx, 'tcx>(
- infcx: &InferCtxt<'cx, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
universal_regions: UniversalRegions<'tcx>,
body: &Body<'tcx>,
promoted: &IndexVec<Promoted, Body<'tcx>>,
@@ -318,8 +318,8 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
}
}
-pub(super) fn dump_mir_results<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+pub(super) fn dump_mir_results<'tcx>(
+ infcx: &InferCtxt<'tcx>,
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
@@ -368,8 +368,8 @@ pub(super) fn dump_mir_results<'a, 'tcx>(
};
}
-pub(super) fn dump_annotation<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+pub(super) fn dump_annotation<'tcx>(
+ infcx: &InferCtxt<'tcx>,
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
index 6e5a96bee..0e71efd6f 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -250,6 +250,7 @@ fn place_components_conflict<'tcx>(
| (ProjectionElem::Index { .. }, _, _)
| (ProjectionElem::ConstantIndex { .. }, _, _)
| (ProjectionElem::Subslice { .. }, _, _)
+ | (ProjectionElem::OpaqueCast { .. }, _, _)
| (ProjectionElem::Downcast { .. }, _, _) => {
// Recursive case. This can still be disjoint on a
// further iteration if this a shallow access and
@@ -317,6 +318,17 @@ fn place_projection_conflict<'tcx>(
debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF");
Overlap::EqualOrDisjoint
}
+ (ProjectionElem::OpaqueCast(v1), ProjectionElem::OpaqueCast(v2)) => {
+ if v1 == v2 {
+ // same type - recur.
+ debug!("place_element_conflict: DISJOINT-OR-EQ-OPAQUE");
+ Overlap::EqualOrDisjoint
+ } else {
+ // Different types. Disjoint!
+ debug!("place_element_conflict: DISJOINT-OPAQUE");
+ Overlap::Disjoint
+ }
+ }
(ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => {
if f1 == f2 {
// same field (e.g., `a.y` vs. `a.y`) - recur.
@@ -520,6 +532,7 @@ fn place_projection_conflict<'tcx>(
| ProjectionElem::Field(..)
| ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
+ | ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..),
_,
diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs
index bdf2becb7..2b50cbac9 100644
--- a/compiler/rustc_borrowck/src/prefixes.rs
+++ b/compiler/rustc_borrowck/src/prefixes.rs
@@ -81,6 +81,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
}
ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. }
+ | ProjectionElem::OpaqueCast { .. }
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Index(_) => {
cursor = cursor_base;
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 244e6e342..8b63294fb 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -15,7 +15,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound,
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
use rustc_middle::mir::{
Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
- ConstraintCategory, Local, Location, ReturnConstraint,
+ ConstraintCategory, Local, Location, ReturnConstraint, TerminatorKind,
};
use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::ObligationCauseCode;
@@ -565,7 +565,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
#[instrument(skip(self, infcx, body, polonius_output), level = "debug")]
pub(super) fn solve(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
polonius_output: Option<Rc<PoloniusOutput>>,
@@ -835,7 +835,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// 'a`. See `TypeTest` for more details.
fn check_type_tests(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
@@ -923,7 +923,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
#[instrument(level = "debug", skip(self, infcx, propagated_outlives_requirements))]
fn try_promote_type_test(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
type_test: &TypeTest<'tcx>,
@@ -1036,7 +1036,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
#[instrument(level = "debug", skip(self, infcx))]
fn try_promote_type_test_subject(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
ty: Ty<'tcx>,
) -> Option<ClosureOutlivesSubject<'tcx>> {
let tcx = infcx.tcx;
@@ -1212,7 +1212,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// `point`.
fn eval_verify_bound(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
generic_ty: Ty<'tcx>,
@@ -1262,7 +1262,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fn eval_if_eq(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
generic_ty: Ty<'tcx>,
lower_bound: RegionVid,
@@ -1398,7 +1398,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// whether any of the constraints were too strong. In particular,
/// we want to check for a case where a universally quantified
/// region exceeded its bounds. Consider:
- /// ```compile_fail,E0312
+ /// ```compile_fail
/// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
/// ```
/// In this case, returning `x` requires `&'a u32 <: &'b u32`
@@ -1451,7 +1451,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// <https://smallcultfollowing.com/babysteps/blog/2019/01/17/polonius-and-region-errors/>
///
/// In the canonical example
- /// ```compile_fail,E0312
+ /// ```compile_fail
/// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
/// ```
/// returning `x` requires `&'a u32 <: &'b u32` and hence we establish (transitively) a
@@ -1718,7 +1718,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fn check_member_constraints(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
errors_buffer: &mut RegionErrors<'tcx>,
) {
let member_constraints = self.member_constraints.clone();
@@ -2236,6 +2236,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
self.universe_causes[&universe].clone()
}
+
+ /// Tries to find the terminator of the loop in which the region 'r' resides.
+ /// Returns the location of the terminator if found.
+ pub(crate) fn find_loop_terminator_location(
+ &self,
+ r: RegionVid,
+ body: &Body<'_>,
+ ) -> Option<Location> {
+ let scc = self.constraint_sccs.scc(r.to_region_vid());
+ let locations = self.scc_values.locations_outlived_by(scc);
+ for location in locations {
+ let bb = &body[location.block];
+ if let Some(terminator) = &bb.terminator {
+ // terminator of a loop should be TerminatorKind::FalseUnwind
+ if let TerminatorKind::FalseUnwind { .. } = terminator.kind {
+ return Some(location);
+ }
+ }
+ }
+ None
+ }
}
impl<'tcx> RegionDefinition<'tcx> {
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 9d088642f..465f353aa 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -2,22 +2,18 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::vec_map::VecMap;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::OpaqueTyOrigin;
-use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
use rustc_infer::infer::TyCtxtInferExt as _;
use rustc_infer::infer::{DefiningAnchor, InferCtxt};
use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
-use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
+use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{
self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt, TypeFoldable,
};
use rustc_span::Span;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::TraitEngineExt as _;
-use crate::session_diagnostics::ConstNotUsedTraitAlias;
-
use super::RegionInferenceContext;
impl<'tcx> RegionInferenceContext<'tcx> {
@@ -63,7 +59,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
#[instrument(level = "debug", skip(self, infcx), ret)]
pub(crate) fn infer_opaque_types(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>> {
let mut result: VecMap<LocalDefId, OpaqueHiddenType<'tcx>> = VecMap::new();
@@ -194,7 +190,7 @@ pub trait InferCtxtExt<'tcx> {
) -> Ty<'tcx>;
}
-impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
/// Given the fully resolved, instantiated type for an opaque
/// type, i.e., the value of an inference variable like C1 or C2
/// (*), computes the "definition type" for an opaque type
@@ -229,31 +225,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
return self.tcx.ty_error();
}
- let OpaqueTypeKey { def_id, substs } = opaque_type_key;
-
- // Use substs to build up a reverse map from regions to their
- // identity mappings. This is necessary because of `impl
- // Trait` lifetimes are computed by replacing existing
- // lifetimes with 'static and remapping only those used in the
- // `impl Trait` return type, resulting in the parameters
- // shifting.
- let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id());
- debug!(?id_substs);
- let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
- substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect();
- debug!("map = {:#?}", map);
-
- // Convert the type from the function into a type valid outside
- // the function, by replacing invalid regions with 'static,
- // after producing an error for each of them.
- let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new(
- self.tcx,
- opaque_type_key,
- map,
- instantiated_ty.ty,
- instantiated_ty.span,
- ));
- debug!(?definition_ty);
+ let definition_ty = instantiated_ty
+ .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false, origin)
+ .ty;
if !check_opaque_type_parameter_valid(
self.tcx,
@@ -266,72 +240,70 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
// on stable and we'd break that.
- if let OpaqueTyOrigin::TyAlias = origin {
- // This logic duplicates most of `check_opaque_meets_bounds`.
- // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
- let param_env = self.tcx.param_env(def_id);
- let body_id = self.tcx.local_def_id_to_hir_id(def_id);
- // HACK This bubble is required for this tests to pass:
- // type-alias-impl-trait/issue-67844-nested-opaque.rs
- self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter(
- move |infcx| {
- // Require the hidden type to be well-formed with only the generics of the opaque type.
- // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
- // hidden type is well formed even without those bounds.
- let predicate =
- ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
- .to_predicate(infcx.tcx);
- let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+ let OpaqueTyOrigin::TyAlias = origin else {
+ return definition_ty;
+ };
+ let def_id = opaque_type_key.def_id;
+ // This logic duplicates most of `check_opaque_meets_bounds`.
+ // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
+ let param_env = self.tcx.param_env(def_id);
+ let body_id = self.tcx.local_def_id_to_hir_id(def_id);
+ // HACK This bubble is required for this tests to pass:
+ // type-alias-impl-trait/issue-67844-nested-opaque.rs
+ let infcx =
+ self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).build();
+ // Require the hidden type to be well-formed with only the generics of the opaque type.
+ // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
+ // hidden type is well formed even without those bounds.
+ let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
+ .to_predicate(infcx.tcx);
+ let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
- // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
- // the bounds that the function supplies.
- match infcx.register_hidden_type(
- OpaqueTypeKey { def_id, substs: id_substs },
- ObligationCause::misc(instantiated_ty.span, body_id),
- param_env,
+ let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id());
+
+ // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
+ // the bounds that the function supplies.
+ let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs);
+ match infcx
+ .at(&ObligationCause::misc(instantiated_ty.span, body_id), param_env)
+ .eq(opaque_ty, definition_ty)
+ {
+ Ok(infer_ok) => {
+ for obligation in infer_ok.obligations {
+ fulfillment_cx.register_predicate_obligation(&infcx, obligation);
+ }
+ }
+ Err(err) => {
+ infcx
+ .err_ctxt()
+ .report_mismatched_types(
+ &ObligationCause::misc(instantiated_ty.span, body_id),
+ opaque_ty,
definition_ty,
- origin,
- ) {
- Ok(infer_ok) => {
- for obligation in infer_ok.obligations {
- fulfillment_cx.register_predicate_obligation(&infcx, obligation);
- }
- }
- Err(err) => {
- infcx
- .report_mismatched_types(
- &ObligationCause::misc(instantiated_ty.span, body_id),
- self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
- definition_ty,
- err,
- )
- .emit();
- }
- }
+ err,
+ )
+ .emit();
+ }
+ }
- fulfillment_cx.register_predicate_obligation(
- &infcx,
- Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
- );
+ fulfillment_cx.register_predicate_obligation(
+ &infcx,
+ Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
+ );
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = fulfillment_cx.select_all_or_error(&infcx);
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = fulfillment_cx.select_all_or_error(&infcx);
- // This is still required for many(half of the tests in ui/type-alias-impl-trait)
- // tests to pass
- let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+ // This is still required for many(half of the tests in ui/type-alias-impl-trait)
+ // tests to pass
+ let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
- if errors.is_empty() {
- definition_ty
- } else {
- infcx.report_fulfillment_errors(&errors, None, false);
- self.tcx.ty_error()
- }
- },
- )
- } else {
+ if errors.is_empty() {
definition_ty
+ } else {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ self.tcx.ty_error()
}
}
}
@@ -427,221 +399,3 @@ fn check_opaque_type_parameter_valid(
}
true
}
-
-struct ReverseMapper<'tcx> {
- tcx: TyCtxt<'tcx>,
-
- key: ty::OpaqueTypeKey<'tcx>,
- map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
- do_not_error: bool,
-
- /// initially `Some`, set to `None` once error has been reported
- hidden_ty: Option<Ty<'tcx>>,
-
- /// Span of function being checked.
- span: Span,
-}
-
-impl<'tcx> ReverseMapper<'tcx> {
- fn new(
- tcx: TyCtxt<'tcx>,
- key: ty::OpaqueTypeKey<'tcx>,
- map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
- hidden_ty: Ty<'tcx>,
- span: Span,
- ) -> Self {
- Self { tcx, key, map, do_not_error: false, hidden_ty: Some(hidden_ty), span }
- }
-
- fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
- assert!(!self.do_not_error);
- self.do_not_error = true;
- let kind = kind.fold_with(self);
- self.do_not_error = false;
- kind
- }
-
- fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
- assert!(!self.do_not_error);
- kind.fold_with(self)
- }
-}
-
-impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
- fn tcx(&self) -> TyCtxt<'tcx> {
- self.tcx
- }
-
- #[instrument(skip(self), level = "debug")]
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- match *r {
- // Ignore bound regions and `'static` regions that appear in the
- // type, we only need to remap regions that reference lifetimes
- // from the function declaration.
- // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
- ty::ReLateBound(..) | ty::ReStatic => return r,
-
- // If regions have been erased (by writeback), don't try to unerase
- // them.
- ty::ReErased => return r,
-
- // The regions that we expect from borrow checking.
- ty::ReEarlyBound(_) | ty::ReFree(_) => {}
-
- ty::RePlaceholder(_) | ty::ReVar(_) => {
- // All of the regions in the type should either have been
- // erased by writeback, or mapped back to named regions by
- // borrow checking.
- bug!("unexpected region kind in opaque type: {:?}", r);
- }
- }
-
- let generics = self.tcx().generics_of(self.key.def_id);
- match self.map.get(&r.into()).map(|k| k.unpack()) {
- Some(GenericArgKind::Lifetime(r1)) => r1,
- Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
- None if self.do_not_error => self.tcx.lifetimes.re_static,
- None if generics.parent.is_some() => {
- if let Some(hidden_ty) = self.hidden_ty.take() {
- unexpected_hidden_region_diagnostic(
- self.tcx,
- self.tcx.def_span(self.key.def_id),
- hidden_ty,
- r,
- self.key,
- )
- .emit();
- }
- self.tcx.lifetimes.re_static
- }
- None => {
- self.tcx
- .sess
- .struct_span_err(self.span, "non-defining opaque type use in defining scope")
- .span_label(
- self.span,
- format!(
- "lifetime `{}` is part of concrete type but not used in \
- parameter list of the `impl Trait` type alias",
- r
- ),
- )
- .emit();
-
- self.tcx().lifetimes.re_static
- }
- }
- }
-
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- match *ty.kind() {
- ty::Closure(def_id, substs) => {
- // I am a horrible monster and I pray for death. When
- // we encounter a closure here, it is always a closure
- // from within the function that we are currently
- // type-checking -- one that is now being encapsulated
- // in an opaque type. Ideally, we would
- // go through the types/lifetimes that it references
- // and treat them just like we would any other type,
- // which means we would error out if we find any
- // reference to a type/region that is not in the
- // "reverse map".
- //
- // **However,** in the case of closures, there is a
- // somewhat subtle (read: hacky) consideration. The
- // problem is that our closure types currently include
- // all the lifetime parameters declared on the
- // enclosing function, even if they are unused by the
- // closure itself. We can't readily filter them out,
- // so here we replace those values with `'empty`. This
- // can't really make a difference to the rest of the
- // compiler; those regions are ignored for the
- // outlives relation, and hence don't affect trait
- // selection or auto traits, and they are erased
- // during codegen.
-
- let generics = self.tcx.generics_of(def_id);
- let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
- if index < generics.parent_count {
- // Accommodate missing regions in the parent kinds...
- self.fold_kind_no_missing_regions_error(kind)
- } else {
- // ...but not elsewhere.
- self.fold_kind_normally(kind)
- }
- }));
-
- self.tcx.mk_closure(def_id, substs)
- }
-
- ty::Generator(def_id, substs, movability) => {
- let generics = self.tcx.generics_of(def_id);
- let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
- if index < generics.parent_count {
- // Accommodate missing regions in the parent kinds...
- self.fold_kind_no_missing_regions_error(kind)
- } else {
- // ...but not elsewhere.
- self.fold_kind_normally(kind)
- }
- }));
-
- self.tcx.mk_generator(def_id, substs, movability)
- }
-
- ty::Param(param) => {
- // Look it up in the substitution list.
- match self.map.get(&ty.into()).map(|k| k.unpack()) {
- // Found it in the substitution list; replace with the parameter from the
- // opaque type.
- Some(GenericArgKind::Type(t1)) => t1,
- Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
- None => {
- debug!(?param, ?self.map);
- self.tcx
- .sess
- .struct_span_err(
- self.span,
- &format!(
- "type parameter `{}` is part of concrete type but not \
- used in parameter list for the `impl Trait` type alias",
- ty
- ),
- )
- .emit();
-
- self.tcx().ty_error()
- }
- }
- }
-
- _ => ty.super_fold_with(self),
- }
- }
-
- fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
- trace!("checking const {:?}", ct);
- // Find a const parameter
- match ct.kind() {
- ty::ConstKind::Param(..) => {
- // Look it up in the substitution list.
- match self.map.get(&ct.into()).map(|k| k.unpack()) {
- // Found it in the substitution list, replace with the parameter from the
- // opaque type.
- Some(GenericArgKind::Const(c1)) => c1,
- Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
- None => {
- self.tcx.sess.emit_err(ConstNotUsedTraitAlias {
- ct: ct.to_string(),
- span: self.span,
- });
-
- self.tcx().const_error(ct.ty())
- }
- }
- }
-
- _ => ct,
- }
- }
-}
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 63b2088f7..f30237690 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -1,8 +1,8 @@
use rustc_index::vec::IndexVec;
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_middle::mir::visit::{MutVisitor, TyContext};
+use rustc_middle::mir::Constant;
use rustc_middle::mir::{Body, Location, Promoted};
-use rustc_middle::mir::{Constant, ConstantKind};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
@@ -10,7 +10,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
/// inference variables, returning the number of variables created.
#[instrument(skip(infcx, body, promoted), level = "debug")]
pub fn renumber_mir<'tcx>(
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
body: &mut Body<'tcx>,
promoted: &mut IndexVec<Promoted, Body<'tcx>>,
) {
@@ -28,7 +28,7 @@ pub fn renumber_mir<'tcx>(
/// Replaces all regions appearing in `value` with fresh inference
/// variables.
#[instrument(skip(infcx), level = "debug")]
-pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: T) -> T
+pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> T
where
T: TypeFoldable<'tcx>,
{
@@ -38,23 +38,8 @@ where
})
}
-// FIXME(valtrees): This function is necessary because `fold_regions`
-// panics for mir constants in the visitor.
-//
-// Once `visit_mir_constant` is removed we can also remove this function
-// and just use `renumber_regions`.
-fn renumber_regions_in_mir_constant<'tcx>(
- infcx: &InferCtxt<'_, 'tcx>,
- value: ConstantKind<'tcx>,
-) -> ConstantKind<'tcx> {
- infcx.tcx.super_fold_regions(value, |_region, _depth| {
- let origin = NllRegionVariableOrigin::Existential { from_forall: false };
- infcx.next_nll_region_var(origin)
- })
-}
-
struct NllVisitor<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> NllVisitor<'a, 'tcx> {
@@ -64,13 +49,6 @@ impl<'a, 'tcx> NllVisitor<'a, 'tcx> {
{
renumber_regions(self.infcx, value)
}
-
- fn renumber_regions_in_mir_constant(
- &mut self,
- value: ConstantKind<'tcx>,
- ) -> ConstantKind<'tcx> {
- renumber_regions_in_mir_constant(self.infcx, value)
- }
}
impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
@@ -103,7 +81,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
#[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_in_mir_constant(literal);
+ constant.literal = self.renumber_regions(literal);
debug!("constant: {:#?}", constant);
}
}
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index 5d750c6ca..cff3089c3 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -1,12 +1,12 @@
use rustc_errors::{IntoDiagnosticArg, MultiSpan};
-use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
use rustc_span::Span;
use crate::diagnostics::RegionName;
-#[derive(SessionDiagnostic)]
-#[diag(borrowck::move_unsized, code = "E0161")]
+#[derive(Diagnostic)]
+#[diag(borrowck_move_unsized, code = "E0161")]
pub(crate) struct MoveUnsized<'tcx> {
pub ty: Ty<'tcx>,
#[primary_span]
@@ -14,8 +14,8 @@ pub(crate) struct MoveUnsized<'tcx> {
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(borrowck::higher_ranked_lifetime_error)]
+#[derive(Diagnostic)]
+#[diag(borrowck_higher_ranked_lifetime_error)]
pub(crate) struct HigherRankedLifetimeError {
#[subdiagnostic]
pub cause: Option<HigherRankedErrorCause>,
@@ -23,23 +23,23 @@ pub(crate) struct HigherRankedLifetimeError {
pub span: Span,
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub(crate) enum HigherRankedErrorCause {
- #[note(borrowck::could_not_prove)]
+ #[note(borrowck_could_not_prove)]
CouldNotProve { predicate: String },
- #[note(borrowck::could_not_normalize)]
+ #[note(borrowck_could_not_normalize)]
CouldNotNormalize { value: String },
}
-#[derive(SessionDiagnostic)]
-#[diag(borrowck::higher_ranked_subtype_error)]
+#[derive(Diagnostic)]
+#[diag(borrowck_higher_ranked_subtype_error)]
pub(crate) struct HigherRankedSubtypeError {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(borrowck::generic_does_not_live_long_enough)]
+#[derive(Diagnostic)]
+#[diag(borrowck_generic_does_not_live_long_enough)]
pub(crate) struct GenericDoesNotLiveLongEnough {
pub kind: String,
#[primary_span]
@@ -47,24 +47,15 @@ pub(crate) struct GenericDoesNotLiveLongEnough {
}
#[derive(LintDiagnostic)]
-#[diag(borrowck::var_does_not_need_mut)]
+#[diag(borrowck_var_does_not_need_mut)]
pub(crate) struct VarNeedNotMut {
#[suggestion_short(applicability = "machine-applicable", code = "")]
pub span: Span,
}
-
-#[derive(SessionDiagnostic)]
-#[diag(borrowck::const_not_used_in_type_alias)]
-pub(crate) struct ConstNotUsedTraitAlias {
- pub ct: String,
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(borrowck::var_cannot_escape_closure)]
+#[derive(Diagnostic)]
+#[diag(borrowck_var_cannot_escape_closure)]
#[note]
-#[note(borrowck::cannot_escape)]
+#[note(cannot_escape)]
pub(crate) struct FnMutError {
#[primary_span]
pub span: Span,
@@ -72,54 +63,54 @@ pub(crate) struct FnMutError {
pub ty_err: FnMutReturnTypeErr,
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub(crate) enum VarHereDenote {
- #[label(borrowck::var_here_captured)]
+ #[label(borrowck_var_here_captured)]
Captured {
#[primary_span]
span: Span,
},
- #[label(borrowck::var_here_defined)]
+ #[label(borrowck_var_here_defined)]
Defined {
#[primary_span]
span: Span,
},
- #[label(borrowck::closure_inferred_mut)]
+ #[label(borrowck_closure_inferred_mut)]
FnMutInferred {
#[primary_span]
span: Span,
},
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub(crate) enum FnMutReturnTypeErr {
- #[label(borrowck::returned_closure_escaped)]
+ #[label(borrowck_returned_closure_escaped)]
ReturnClosure {
#[primary_span]
span: Span,
},
- #[label(borrowck::returned_async_block_escaped)]
+ #[label(borrowck_returned_async_block_escaped)]
ReturnAsyncBlock {
#[primary_span]
span: Span,
},
- #[label(borrowck::returned_ref_escaped)]
+ #[label(borrowck_returned_ref_escaped)]
ReturnRef {
#[primary_span]
span: Span,
},
}
-#[derive(SessionDiagnostic)]
-#[diag(borrowck::lifetime_constraints_error)]
+#[derive(Diagnostic)]
+#[diag(borrowck_lifetime_constraints_error)]
pub(crate) struct LifetimeOutliveErr {
#[primary_span]
pub span: Span,
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub(crate) enum LifetimeReturnCategoryErr<'a> {
- #[label(borrowck::returned_lifetime_wrong)]
+ #[label(borrowck_returned_lifetime_wrong)]
WrongReturn {
#[primary_span]
span: Span,
@@ -127,7 +118,7 @@ pub(crate) enum LifetimeReturnCategoryErr<'a> {
outlived_fr_name: RegionName,
fr_name: &'a RegionName,
},
- #[label(borrowck::returned_lifetime_short)]
+ #[label(borrowck_returned_lifetime_short)]
ShortReturn {
#[primary_span]
span: Span,
@@ -149,9 +140,9 @@ impl IntoDiagnosticArg for RegionName {
}
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub(crate) enum RequireStaticErr {
- #[note(borrowck::used_impl_require_static)]
+ #[note(borrowck_used_impl_require_static)]
UsedImpl {
#[primary_span]
multi_span: MultiSpan,
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 9271a2f4d..a581726a1 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -52,11 +52,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Some(error_info) => error_info.to_universe_info(old_universe),
None => UniverseInfo::other(),
};
- for u in old_universe..universe {
- self.borrowck_context
- .constraints
- .universe_causes
- .insert(u + 1, universe_info.clone());
+ for u in (old_universe + 1)..=universe {
+ self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone());
}
}
@@ -71,15 +68,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
where
T: TypeFoldable<'tcx>,
{
+ let old_universe = self.infcx.universe();
+
let (instantiated, _) =
self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
- for u in 0..canonical.max_universe.as_u32() {
- let info = UniverseInfo::other();
- self.borrowck_context
- .constraints
- .universe_causes
- .insert(ty::UniverseIndex::from_u32(u), info);
+ for u in (old_universe + 1)..=self.infcx.universe() {
+ self.borrowck_context.constraints.universe_causes.insert(u, UniverseInfo::other());
}
instantiated
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index 71eae0583..d5bfc2f52 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -19,7 +19,7 @@ use crate::{
};
pub(crate) struct ConstraintConversion<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
tcx: TyCtxt<'tcx>,
universal_regions: &'a UniversalRegions<'tcx>,
/// Each RBP `GK: 'a` is assumed to be true. These encode
@@ -43,7 +43,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
pub(crate) fn new(
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
universal_regions: &'a UniversalRegions<'tcx>,
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
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 f1b1c33a1..029095926 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,6 @@ 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::DUMMY_SP;
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
use std::rc::Rc;
use type_op::TypeOpOutput;
@@ -48,7 +47,7 @@ pub(crate) struct CreateResult<'tcx> {
}
pub(crate) fn create<'tcx>(
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
universal_regions: &Rc<UniversalRegions<'tcx>>,
@@ -197,7 +196,7 @@ impl UniversalRegionRelations<'_> {
}
struct UniversalRegionRelationsBuilder<'this, 'tcx> {
- infcx: &'this InferCtxt<'this, 'tcx>,
+ infcx: &'this InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
universal_regions: Rc<UniversalRegions<'tcx>>,
implicit_region_bound: ty::Region<'tcx>,
@@ -219,6 +218,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
}
pub(crate) fn create(mut self) -> CreateResult<'tcx> {
+ let span = self.infcx.tcx.def_span(self.universal_regions.defining_ty.def_id());
let unnormalized_input_output_tys = self
.universal_regions
.unnormalized_input_tys
@@ -250,7 +250,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
self.infcx
.tcx
.sess
- .delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty));
+ .delay_span_bug(span, &format!("failed to normalize {:?}", ty));
TypeOpOutput {
output: self.infcx.tcx.ty_error(),
constraints: None,
@@ -301,8 +301,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
&self.region_bound_pairs,
self.implicit_region_bound,
self.param_env,
- Locations::All(DUMMY_SP),
- DUMMY_SP,
+ Locations::All(span),
+ span,
ConstraintCategory::Internal,
&mut self.constraints,
)
@@ -362,6 +362,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
self.region_bound_pairs
.insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
}
+
+ OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
+ self.region_bound_pairs
+ .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
+ }
}
}
}
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 4431a2e8e..a66ddd27d 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -7,16 +7,11 @@
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
//! contain revealed `impl Trait` values).
-use crate::type_check::constraint_conversion::ConstraintConversion;
use rustc_index::vec::Idx;
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::mir::*;
use rustc_middle::ty::Ty;
use rustc_span::Span;
-use rustc_span::DUMMY_SP;
-use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
-use rustc_trait_selection::traits::query::Fallible;
-use type_op::TypeOpOutput;
use crate::universal_regions::UniversalRegions;
@@ -185,7 +180,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
- #[instrument(skip(self, span), level = "debug")]
+ #[instrument(skip(self), level = "debug")]
fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
if let Err(_) =
self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
@@ -194,13 +189,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
// like to normalize *before* inserting into `local_decls`, but
// doing so ends up causing some other trouble.
- let b = match self.normalize_and_add_constraints(b) {
- Ok(n) => n,
- Err(_) => {
- debug!("equate_inputs_and_outputs: NoSolution");
- b
- }
- };
+ let b = self.normalize(b, Locations::All(span));
// Note: if we have to introduce new placeholders during normalization above, then we won't have
// added those universes to the universe info, which we would want in `relate_tys`.
@@ -218,28 +207,4 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
}
-
- pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible<Ty<'tcx>> {
- let TypeOpOutput { output: norm_ty, constraints, .. } =
- self.param_env.and(type_op::normalize::Normalize::new(t)).fully_perform(self.infcx)?;
-
- debug!("{:?} normalized to {:?}", t, norm_ty);
-
- for data in constraints {
- ConstraintConversion::new(
- self.infcx,
- &self.borrowck_context.universal_regions,
- &self.region_bound_pairs,
- self.implicit_region_bound,
- self.param_env,
- Locations::All(DUMMY_SP),
- DUMMY_SP,
- ConstraintCategory::Internal,
- &mut self.borrowck_context.constraints,
- )
- .convert_all(&*data);
- }
-
- Ok(norm_ty)
- }
}
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 3713ec3f5..3c1c3ab45 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -123,7 +123,7 @@ mod relate_tys;
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
/// - `elements` -- MIR region map
pub(crate) fn type_check<'mir, 'tcx>(
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
promoted: &IndexVec<Promoted, Body<'tcx>>,
@@ -138,8 +138,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
use_polonius: bool,
) -> MirTypeckResults<'tcx> {
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
- let mut universe_causes = FxHashMap::default();
- universe_causes.insert(ty::UniverseIndex::from_u32(0), UniverseInfo::other());
let mut constraints = MirTypeckRegionConstraints {
placeholder_indices: PlaceholderIndices::default(),
placeholder_index_to_region: IndexVec::default(),
@@ -148,7 +146,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
member_constraints: MemberConstraintSet::default(),
closure_bounds_mapping: Default::default(),
type_tests: Vec::default(),
- universe_causes,
+ universe_causes: FxHashMap::default(),
};
let CreateResult {
@@ -165,9 +163,8 @@ pub(crate) fn type_check<'mir, 'tcx>(
debug!(?normalized_inputs_and_output);
- for u in ty::UniverseIndex::ROOT..infcx.universe() {
- let info = UniverseInfo::other();
- constraints.universe_causes.insert(u, info);
+ for u in ty::UniverseIndex::ROOT..=infcx.universe() {
+ constraints.universe_causes.insert(u, UniverseInfo::other());
}
let mut borrowck_context = BorrowCheckContext {
@@ -236,7 +233,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
.unwrap();
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_infer_types_or_consts() {
+ if hidden_type.has_non_region_infer() {
infcx.tcx.sess.delay_span_bug(
decl.hidden_type.span,
&format!("could not resolve {:#?}", hidden_type.ty.kind()),
@@ -428,12 +425,18 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
}
if let ty::FnDef(def_id, substs) = *constant.literal.ty().kind() {
+ // const_trait_impl: use a non-const param env when checking that a FnDef type is well formed.
+ // this is because the well-formedness of the function does not need to be proved to have `const`
+ // impls for trait bounds.
let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
+ let prev = self.cx.param_env;
+ self.cx.param_env = prev.without_const();
self.cx.normalize_and_prove_instantiated_predicates(
def_id,
instantiated_predicates,
locations,
);
+ self.cx.param_env = prev;
}
}
}
@@ -581,6 +584,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
// modify their locations.
let all_facts = &mut None;
let mut constraints = Default::default();
+ let mut type_tests = Default::default();
let mut closure_bounds = Default::default();
let mut liveness_constraints =
LivenessValues::new(Rc::new(RegionValueElements::new(&promoted_body)));
@@ -592,6 +596,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
&mut this.cx.borrowck_context.constraints.outlives_constraints,
&mut constraints,
);
+ mem::swap(&mut this.cx.borrowck_context.constraints.type_tests, &mut type_tests);
mem::swap(
&mut this.cx.borrowck_context.constraints.closure_bounds_mapping,
&mut closure_bounds,
@@ -616,6 +621,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
swap_constraints(self);
let locations = location.to_locations();
+
+ // Use location of promoted const in collected constraints
+ for type_test in type_tests.iter() {
+ let mut type_test = type_test.clone();
+ type_test.locations = locations;
+ self.cx.borrowck_context.constraints.type_tests.push(type_test)
+ }
for constraint in constraints.outlives().iter() {
let mut constraint = constraint.clone();
constraint.locations = locations;
@@ -764,6 +776,19 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}
PlaceTy::from_ty(fty)
}
+ ProjectionElem::OpaqueCast(ty) => {
+ let ty = self.sanitize_type(place, ty);
+ let ty = self.cx.normalize(ty, location);
+ self.cx
+ .eq_types(
+ base.ty,
+ ty,
+ location.to_locations(),
+ ConstraintCategory::TypeAnnotation,
+ )
+ .unwrap();
+ PlaceTy::from_ty(ty)
+ }
}
}
@@ -857,7 +882,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
/// way, it accrues region constraints -- these can later be used by
/// NLL region checking.
struct TypeChecker<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
last_span: Span,
body: &'a Body<'tcx>,
@@ -927,7 +952,7 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> {
impl<'tcx> MirTypeckRegionConstraints<'tcx> {
fn placeholder_region(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
placeholder: ty::PlaceholderRegion,
) -> ty::Region<'tcx> {
let placeholder_index = self.placeholder_indices.insert(placeholder);
@@ -1011,7 +1036,7 @@ impl Locations {
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
fn new(
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
body: &'a Body<'tcx>,
param_env: ty::ParamEnv<'tcx>,
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
@@ -1170,10 +1195,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
tcx,
self.param_env,
proj,
- |this, field, ()| {
+ |this, field, _| {
let ty = this.field_ty(tcx, field);
self.normalize(ty, locations)
},
+ |_, _| unreachable!(),
);
curr_projected_ty = projected_ty;
}
@@ -1604,7 +1630,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let op_arg_ty = self.normalize(op_arg_ty, term_location);
let category = if from_hir_call {
- ConstraintCategory::CallArgument(func_ty)
+ ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty))
} else {
ConstraintCategory::Boring
};
@@ -1757,7 +1783,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// `Sized` bound in no way depends on precise regions, so this
// shouldn't affect `is_sized`.
let erased_ty = tcx.erase_regions(ty);
- if !erased_ty.is_sized(tcx.at(span), self.param_env) {
+ if !erased_ty.is_sized(tcx, self.param_env) {
// in current MIR construction, all non-control-flow rvalue
// expressions evaluate through `as_temp` or `into` a return
// slot or local, so to find all unsized rvalues it is enough
@@ -2189,25 +2215,104 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
}
-
- CastKind::Misc => {
+ CastKind::IntToInt => {
let ty_from = op.ty(body, tcx);
let cast_ty_from = CastTy::from_ty(ty_from);
let cast_ty_to = CastTy::from_ty(*ty);
- // Misc casts are either between floats and ints, or one ptr type to another.
match (cast_ty_from, cast_ty_to) {
- (
- Some(CastTy::Int(_) | CastTy::Float),
- Some(CastTy::Int(_) | CastTy::Float),
- )
- | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Ptr(_))) => (),
+ (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => (),
_ => {
span_mirbug!(
self,
rvalue,
- "Invalid Misc cast {:?} -> {:?}",
+ "Invalid IntToInt cast {:?} -> {:?}",
ty_from,
- ty,
+ ty
+ )
+ }
+ }
+ }
+ CastKind::IntToFloat => {
+ let ty_from = op.ty(body, tcx);
+ let cast_ty_from = CastTy::from_ty(ty_from);
+ let cast_ty_to = CastTy::from_ty(*ty);
+ match (cast_ty_from, cast_ty_to) {
+ (Some(CastTy::Int(_)), Some(CastTy::Float)) => (),
+ _ => {
+ span_mirbug!(
+ self,
+ rvalue,
+ "Invalid IntToFloat cast {:?} -> {:?}",
+ ty_from,
+ ty
+ )
+ }
+ }
+ }
+ CastKind::FloatToInt => {
+ let ty_from = op.ty(body, tcx);
+ let cast_ty_from = CastTy::from_ty(ty_from);
+ let cast_ty_to = CastTy::from_ty(*ty);
+ match (cast_ty_from, cast_ty_to) {
+ (Some(CastTy::Float), Some(CastTy::Int(_))) => (),
+ _ => {
+ span_mirbug!(
+ self,
+ rvalue,
+ "Invalid FloatToInt cast {:?} -> {:?}",
+ ty_from,
+ ty
+ )
+ }
+ }
+ }
+ CastKind::FloatToFloat => {
+ let ty_from = op.ty(body, tcx);
+ let cast_ty_from = CastTy::from_ty(ty_from);
+ let cast_ty_to = CastTy::from_ty(*ty);
+ match (cast_ty_from, cast_ty_to) {
+ (Some(CastTy::Float), Some(CastTy::Float)) => (),
+ _ => {
+ span_mirbug!(
+ self,
+ rvalue,
+ "Invalid FloatToFloat cast {:?} -> {:?}",
+ ty_from,
+ ty
+ )
+ }
+ }
+ }
+ CastKind::FnPtrToPtr => {
+ let ty_from = op.ty(body, tcx);
+ let cast_ty_from = CastTy::from_ty(ty_from);
+ let cast_ty_to = CastTy::from_ty(*ty);
+ match (cast_ty_from, cast_ty_to) {
+ (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => (),
+ _ => {
+ span_mirbug!(
+ self,
+ rvalue,
+ "Invalid FnPtrToPtr cast {:?} -> {:?}",
+ ty_from,
+ ty
+ )
+ }
+ }
+ }
+ CastKind::PtrToPtr => {
+ let ty_from = op.ty(body, tcx);
+ let cast_ty_from = CastTy::from_ty(ty_from);
+ let cast_ty_to = CastTy::from_ty(*ty);
+ match (cast_ty_from, cast_ty_to) {
+ (Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_))) => (),
+ _ => {
+ span_mirbug!(
+ self,
+ rvalue,
+ "Invalid PtrToPtr cast {:?} -> {:?}",
+ ty_from,
+ ty
)
}
}
@@ -2503,6 +2608,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
ProjectionElem::Field(..)
| ProjectionElem::Downcast(..)
+ | ProjectionElem::OpaqueCast(..)
| ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {
@@ -2723,7 +2829,7 @@ 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>> {
+ 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() })
})?;
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index c97a6a1a6..4f2dc263b 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -1,6 +1,6 @@
use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
use rustc_infer::infer::NllRegionVariableOrigin;
-use rustc_infer::traits::ObligationCause;
+use rustc_infer::traits::PredicateObligations;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::TypeRelation;
@@ -155,27 +155,16 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
true
}
- fn register_opaque_type(
+ fn register_opaque_type_obligations(
&mut self,
- a: Ty<'tcx>,
- b: Ty<'tcx>,
- a_is_expected: bool,
+ obligations: PredicateObligations<'tcx>,
) -> Result<(), TypeError<'tcx>> {
- let param_env = self.param_env();
- let span = self.span();
- let def_id = self.type_checker.body.source.def_id().expect_local();
- let body_id = self.type_checker.tcx().hir().local_def_id_to_hir_id(def_id);
- let cause = ObligationCause::misc(span, body_id);
self.type_checker
.fully_perform_op(
self.locations,
self.category,
InstantiateOpaqueType {
- obligations: self
- .type_checker
- .infcx
- .handle_opaque_type(a, b, a_is_expected, &cause, param_env)?
- .obligations,
+ 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 8cf9ed53d..2beb5e0ab 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -22,8 +22,8 @@ use rustc_hir::{BodyOwnerKind, HirId};
use rustc_index::vec::{Idx, IndexVec};
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
+use rustc_middle::ty::{InternalSubsts, SubstsRef};
use std::iter;
use crate::nll::ToRegionVid;
@@ -219,7 +219,7 @@ impl<'tcx> UniversalRegions<'tcx> {
/// signature. This will also compute the relationships that are
/// known between those regions.
pub fn new(
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
mir_def: ty::WithOptConstParam<LocalDefId>,
param_env: ty::ParamEnv<'tcx>,
) -> Self {
@@ -382,7 +382,7 @@ impl<'tcx> UniversalRegions<'tcx> {
}
struct UniversalRegionsBuilder<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
mir_def: ty::WithOptConstParam<LocalDefId>,
mir_hir_id: HirId,
param_env: ty::ParamEnv<'tcx>,
@@ -414,7 +414,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
- // If this is is a 'root' body (not a closure/generator/inline const), then
+ // 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 {
@@ -699,7 +699,7 @@ trait InferCtxtExt<'tcx> {
);
}
-impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
fn replace_free_regions_with_nll_infer_vars<T>(
&self,
origin: NllRegionVariableOrigin,
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index f80215a3c..bb6839360 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -58,6 +58,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
/// Builds the whole `assert!` expression. For example, `let elem = 1; assert!(elem == 1);` expands to:
///
/// ```rust
+ /// #![feature(generic_assert_internals)]
/// let elem = 1;
/// {
/// #[allow(unused_imports)]
@@ -70,7 +71,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
/// __local_bind0
/// } == 1
/// ) {
- /// panic!("Assertion failed: elem == 1\nWith captures:\n elem = {}", __capture0)
+ /// panic!("Assertion failed: elem == 1\nWith captures:\n elem = {:?}", __capture0)
/// }
/// }
/// ```
@@ -241,8 +242,8 @@ impl<'cx, 'a> Context<'cx, 'a> {
self.manage_cond_expr(prefix);
self.manage_cond_expr(suffix);
}
- ExprKind::MethodCall(_, ref mut local_exprs, _) => {
- for local_expr in local_exprs.iter_mut().skip(1) {
+ ExprKind::MethodCall(_, _,ref mut local_exprs, _) => {
+ for local_expr in local_exprs.iter_mut() {
self.manage_cond_expr(local_expr);
}
}
@@ -378,14 +379,12 @@ impl<'cx, 'a> Context<'cx, 'a> {
id: DUMMY_NODE_ID,
ident: Ident::new(sym::try_capture, self.span),
},
- vec![
- expr_paren(self.cx, self.span, self.cx.expr_addr_of(self.span, wrapper)),
- expr_addr_of_mut(
- self.cx,
- self.span,
- self.cx.expr_path(Path::from_ident(capture)),
- ),
- ],
+ expr_paren(self.cx, self.span, self.cx.expr_addr_of(self.span, wrapper)),
+ vec![expr_addr_of_mut(
+ self.cx,
+ self.span,
+ self.cx.expr_path(Path::from_ident(capture)),
+ )],
self.span,
))
.add_trailing_semicolon();
@@ -443,10 +442,11 @@ fn expr_addr_of_mut(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> {
fn expr_method_call(
cx: &ExtCtxt<'_>,
path: PathSegment,
+ receiver: P<Expr>,
args: Vec<P<Expr>>,
span: Span,
) -> P<Expr> {
- cx.expr(span, ExprKind::MethodCall(path, args, span))
+ cx.expr(span, ExprKind::MethodCall(path, receiver, args, span))
}
fn expr_paren(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> {
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index 9046bf130..5638c2f61 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -8,7 +8,7 @@ use rustc_ast::tokenstream::TokenStream;
use rustc_attr as attr;
use rustc_errors::PResult;
use rustc_expand::base::{self, *};
-use rustc_macros::SessionDiagnostic;
+use rustc_macros::Diagnostic;
use rustc_span::Span;
pub fn expand_cfg(
@@ -35,16 +35,16 @@ pub fn expand_cfg(
}
}
-#[derive(SessionDiagnostic)]
-#[diag(builtin_macros::requires_cfg_pattern)]
+#[derive(Diagnostic)]
+#[diag(builtin_macros_requires_cfg_pattern)]
struct RequiresCfgPattern {
#[primary_span]
#[label]
span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(builtin_macros::expected_one_cfg_pattern)]
+#[derive(Diagnostic)]
+#[diag(builtin_macros_expected_one_cfg_pattern)]
struct OneCfgPattern {
#[primary_span]
span: Span,
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index e673dff0d..750f1fe12 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -7,6 +7,7 @@ use rustc_ast::visit::Visitor;
use rustc_ast::NodeId;
use rustc_ast::{mut_visit, visit};
use rustc_ast::{Attribute, HasAttrs, HasTokens};
+use rustc_errors::PResult;
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_expand::config::StripUnconfigured;
use rustc_expand::configure;
@@ -144,33 +145,34 @@ impl CfgEval<'_, '_> {
// the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
// process is lossless, so this process is invisible to proc-macros.
- let parse_annotatable_with: fn(&mut Parser<'_>) -> _ = match annotatable {
- Annotatable::Item(_) => {
- |parser| Annotatable::Item(parser.parse_item(ForceCollect::Yes).unwrap().unwrap())
- }
- Annotatable::TraitItem(_) => |parser| {
- Annotatable::TraitItem(
- parser.parse_trait_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
- )
- },
- Annotatable::ImplItem(_) => |parser| {
- Annotatable::ImplItem(
- parser.parse_impl_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
- )
- },
- Annotatable::ForeignItem(_) => |parser| {
- Annotatable::ForeignItem(
- parser.parse_foreign_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
- )
- },
- Annotatable::Stmt(_) => |parser| {
- Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes).unwrap().unwrap()))
- },
- Annotatable::Expr(_) => {
- |parser| Annotatable::Expr(parser.parse_expr_force_collect().unwrap())
- }
- _ => unreachable!(),
- };
+ let parse_annotatable_with: for<'a> fn(&mut Parser<'a>) -> PResult<'a, _> =
+ match annotatable {
+ Annotatable::Item(_) => {
+ |parser| Ok(Annotatable::Item(parser.parse_item(ForceCollect::Yes)?.unwrap()))
+ }
+ Annotatable::TraitItem(_) => |parser| {
+ Ok(Annotatable::TraitItem(
+ parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap(),
+ ))
+ },
+ Annotatable::ImplItem(_) => |parser| {
+ Ok(Annotatable::ImplItem(
+ parser.parse_impl_item(ForceCollect::Yes)?.unwrap().unwrap(),
+ ))
+ },
+ Annotatable::ForeignItem(_) => |parser| {
+ Ok(Annotatable::ForeignItem(
+ parser.parse_foreign_item(ForceCollect::Yes)?.unwrap().unwrap(),
+ ))
+ },
+ Annotatable::Stmt(_) => |parser| {
+ Ok(Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes)?.unwrap())))
+ },
+ Annotatable::Expr(_) => {
+ |parser| Ok(Annotatable::Expr(parser.parse_expr_force_collect()?))
+ }
+ _ => unreachable!(),
+ };
// 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`)
// to `None`-delimited groups containing the corresponding tokens. This
@@ -193,7 +195,13 @@ impl CfgEval<'_, '_> {
let mut parser =
rustc_parse::stream_to_parser(&self.cfg.sess.parse_sess, orig_tokens, None);
parser.capture_cfg = true;
- annotatable = parse_annotatable_with(&mut parser);
+ match parse_annotatable_with(&mut parser) {
+ Ok(a) => annotatable = a,
+ Err(mut err) => {
+ err.emit();
+ return Some(annotatable);
+ }
+ }
// Now that we have our re-parsed `AttrTokenStream`, recursively configuring
// our attribute target will correctly the tokens as well.
@@ -202,8 +210,15 @@ impl CfgEval<'_, '_> {
}
impl MutVisitor for CfgEval<'_, '_> {
+ #[instrument(level = "trace", skip(self))]
fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
- self.cfg.configure_expr(expr);
+ self.cfg.configure_expr(expr, false);
+ mut_visit::noop_visit_expr(expr, self);
+ }
+
+ #[instrument(level = "trace", skip(self))]
+ fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) {
+ self.cfg.configure_expr(expr, true);
mut_visit::noop_visit_expr(expr, self);
}
diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
index 77e0b6c55..7bd344467 100644
--- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
@@ -16,6 +16,7 @@ pub fn expand_deriving_copy(
let trait_def = TraitDef {
span,
path: path_std!(marker::Copy),
+ skip_path_as_bound: false,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: true,
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index c7f2d95e7..fa8685f5f 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -72,6 +72,7 @@ pub fn expand_deriving_clone(
let trait_def = TraitDef {
span,
path: path_std!(clone::Clone),
+ skip_path_as_bound: false,
additional_bounds: bounds,
generics: Bounds::empty(),
supports_unions: true,
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index 5b556c5c9..eab67b0d3 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -25,6 +25,7 @@ pub fn expand_deriving_eq(
let trait_def = TraitDef {
span,
path: path_std!(cmp::Eq),
+ skip_path_as_bound: false,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: true,
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
index 726258695..7f117981a 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
@@ -19,6 +19,7 @@ pub fn expand_deriving_ord(
let trait_def = TraitDef {
span,
path: path_std!(cmp::Ord),
+ skip_path_as_bound: false,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: false,
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
index 42ee65b57..236cbccaf 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
@@ -83,6 +83,7 @@ pub fn expand_deriving_partial_eq(
let trait_def = TraitDef {
span,
path: path_std!(cmp::PartialEq),
+ skip_path_as_bound: false,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: false,
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
index 516892aed..4173403a1 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
@@ -37,6 +37,7 @@ pub fn expand_deriving_partial_ord(
let trait_def = TraitDef {
span,
path: path_std!(cmp::PartialOrd),
+ skip_path_as_bound: false,
additional_bounds: vec![],
generics: Bounds::empty(),
supports_unions: false,
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index 4af7fd816..2cf614ed9 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -20,6 +20,7 @@ pub fn expand_deriving_debug(
let trait_def = TraitDef {
span,
path: path_std!(fmt::Debug),
+ skip_path_as_bound: false,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: false,
diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
index 7174dbbe7..d669f6168 100644
--- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
@@ -23,6 +23,7 @@ pub fn expand_deriving_rustc_decodable(
let trait_def = TraitDef {
span,
path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global),
+ skip_path_as_bound: false,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: false,
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index a94c8a996..17df9fb27 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -24,6 +24,7 @@ pub fn expand_deriving_default(
let trait_def = TraitDef {
span,
path: Path::new(vec![kw::Default, sym::Default]),
+ skip_path_as_bound: has_a_default_variant(item),
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: false,
@@ -262,3 +263,22 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, '
}
}
}
+
+fn has_a_default_variant(item: &Annotatable) -> bool {
+ struct HasDefaultAttrOnVariant {
+ found: bool,
+ }
+
+ impl<'ast> rustc_ast::visit::Visitor<'ast> for HasDefaultAttrOnVariant {
+ fn visit_variant(&mut self, v: &'ast rustc_ast::Variant) {
+ if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) {
+ self.found = true;
+ }
+ // no need to subrecurse.
+ }
+ }
+
+ let mut visitor = HasDefaultAttrOnVariant { found: false };
+ item.visit_with(&mut visitor);
+ visitor.found
+}
diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
index b220e5423..f83f58b97 100644
--- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
@@ -107,6 +107,7 @@ pub fn expand_deriving_rustc_encodable(
let trait_def = TraitDef {
span,
path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global),
+ skip_path_as_bound: false,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: false,
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 3cc160adb..16ee3aa89 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -174,6 +174,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use std::cell::RefCell;
use std::iter;
+use std::ops::Not;
use std::vec;
use thin_vec::thin_vec;
use ty::{Bounds, Path, Ref, Self_, Ty};
@@ -187,6 +188,9 @@ pub struct TraitDef<'a> {
/// Path of the trait, including any type parameters
pub path: Path,
+ /// Whether to skip adding the current trait as a bound to the type parameters of the type.
+ pub skip_path_as_bound: bool,
+
/// Additional bounds required of any type parameters of the type,
/// other than the current trait
pub additional_bounds: Vec<Ty>,
@@ -562,7 +566,7 @@ impl<'a> TraitDef<'a> {
tokens: None,
},
attrs: ast::AttrVec::new(),
- kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAlias {
+ kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias {
defaultness: ast::Defaultness::Final,
generics: Generics::default(),
where_clauses: (
@@ -596,7 +600,7 @@ impl<'a> TraitDef<'a> {
cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))
}).chain(
// require the current trait
- iter::once(cx.trait_bound(trait_path.clone()))
+ self.skip_path_as_bound.not().then(|| cx.trait_bound(trait_path.clone()))
).chain(
// also add in any bounds from the declaration
param.bounds.iter().cloned()
@@ -1110,6 +1114,11 @@ impl<'a> MethodDef<'a> {
/// ```
/// is equivalent to:
/// ```
+ /// #![feature(core_intrinsics)]
+ /// enum A {
+ /// A1,
+ /// A2(i32)
+ /// }
/// impl ::core::cmp::PartialEq for A {
/// #[inline]
/// fn eq(&self, other: &A) -> bool {
diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs
index f1f02e7ce..6e9d5f08b 100644
--- a/compiler/rustc_builtin_macros/src/deriving/hash.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs
@@ -22,6 +22,7 @@ pub fn expand_deriving_hash(
let hash_trait_def = TraitDef {
span,
path,
+ skip_path_as_bound: false,
additional_bounds: Vec::new(),
generics: Bounds::empty(),
supports_unions: false,
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index a65d0bad6..ee346047a 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -131,6 +131,8 @@ fn inject_impl_of_structural_trait(
// Create generics param list for where clauses and impl headers
let mut generics = generics.clone();
+ let ctxt = span.ctxt();
+
// Create the type of `self`.
//
// in addition, remove defaults from generic params (impls cannot have them).
@@ -138,16 +140,18 @@ fn inject_impl_of_structural_trait(
.params
.iter_mut()
.map(|param| match &mut param.kind {
- ast::GenericParamKind::Lifetime => {
- ast::GenericArg::Lifetime(cx.lifetime(span, param.ident))
- }
+ ast::GenericParamKind::Lifetime => ast::GenericArg::Lifetime(
+ cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident),
+ ),
ast::GenericParamKind::Type { default } => {
*default = None;
- ast::GenericArg::Type(cx.ty_ident(span, param.ident))
+ ast::GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
}
ast::GenericParamKind::Const { ty: _, kw_span: _, default } => {
*default = None;
- ast::GenericArg::Const(cx.const_ident(span, param.ident))
+ ast::GenericArg::Const(
+ cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident),
+ )
}
})
.collect();
@@ -174,6 +178,8 @@ fn inject_impl_of_structural_trait(
})
.cloned(),
);
+ // Mark as `automatically_derived` to avoid some silly lints.
+ attrs.push(cx.attribute(cx.meta_word(span, sym::automatically_derived)));
let newitem = cx.item(
span,
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 210048710..8b07c1106 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -1,271 +1,42 @@
-use ArgumentType::*;
-use Position::*;
-
-use rustc_ast as ast;
use rustc_ast::ptr::P;
+use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::visit::{self, Visitor};
-use rustc_ast::{token, BlockCheckMode, UnsafeSource};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_ast::Expr;
+use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, Applicability, MultiSpan, PResult};
use rustc_expand::base::{self, *};
use rustc_parse_format as parse;
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{BytePos, InnerSpan, Span};
-use smallvec::SmallVec;
use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId};
-use rustc_parse_format::Count;
-use std::borrow::Cow;
-use std::collections::hash_map::Entry;
-
-#[derive(PartialEq)]
-enum ArgumentType {
- Placeholder(&'static str),
- Count,
-}
-
-enum Position {
- Exact(usize),
- Capture(usize),
- Named(Symbol, InnerSpan),
-}
-
-/// Indicates how positional named argument (i.e. an named argument which is used by position
-/// instead of by name) is used in format string
-/// * `Arg` is the actual argument to print
-/// * `Width` is width format argument
-/// * `Precision` is precion format argument
-/// Example: `{Arg:Width$.Precision$}
-#[derive(Debug, Eq, PartialEq)]
-enum PositionalNamedArgType {
- Arg,
- Width,
- Precision,
-}
-
-/// Contains information necessary to create a lint for a positional named argument
-#[derive(Debug)]
-struct PositionalNamedArg {
- ty: PositionalNamedArgType,
- /// The piece of the using this argument (multiple pieces can use the same argument)
- cur_piece: usize,
- /// The InnerSpan for in the string to be replaced with the named argument
- /// This will be None when the position is implicit
- inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
- /// The name to use instead of the position
- replacement: Symbol,
- /// The span for the positional named argument (so the lint can point a message to it)
- positional_named_arg_span: Span,
- has_formatting: bool,
-}
-
-impl PositionalNamedArg {
- /// Determines:
- /// 1) span to be replaced with the name of the named argument and
- /// 2) span to be underlined for error messages
- fn get_positional_arg_spans(&self, cx: &Context<'_, '_>) -> (Option<Span>, Option<Span>) {
- if let Some(inner_span) = &self.inner_span_to_replace {
- let span =
- cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end });
- (Some(span), Some(span))
- } else if self.ty == PositionalNamedArgType::Arg {
- // In the case of a named argument whose position is implicit, if the argument *has*
- // formatting, there will not be a span to replace. Instead, we insert the name after
- // the `{`, which will be the first character of arg_span. If the argument does *not*
- // have formatting, there may or may not be a span to replace. This is because
- // whitespace is allowed in arguments without formatting (such as `format!("{ }", 1);`)
- // but is not allowed in arguments with formatting (an error will be generated in cases
- // like `format!("{ :1.1}", 1.0f32);`.
- // For the message span, if there is formatting, we want to use the opening `{` and the
- // next character, which will the `:` indicating the start of formatting. If there is
- // not any formatting, we want to underline the entire span.
- cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| {
- if self.has_formatting {
- (
- Some(arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo()),
- Some(arg_span.with_hi(arg_span.lo() + BytePos(2))),
- )
- } else {
- let replace_start = arg_span.lo() + BytePos(1);
- let replace_end = arg_span.hi() - BytePos(1);
- let to_replace = arg_span.with_lo(replace_start).with_hi(replace_end);
- (Some(to_replace), Some(*arg_span))
- }
- })
- } else {
- (None, None)
- }
- }
-}
-
-/// Encapsulates all the named arguments that have been used positionally
-#[derive(Debug)]
-struct PositionalNamedArgsLint {
- positional_named_args: Vec<PositionalNamedArg>,
-}
-
-impl PositionalNamedArgsLint {
- /// For a given positional argument, check if the index is for a named argument.
- ///
- /// Since positional arguments are required to come before named arguments, if the positional
- /// index is greater than or equal to the start of named arguments, we know it's a named
- /// argument used positionally.
- ///
- /// Example:
- /// println!("{} {} {2}", 0, a=1, b=2);
- ///
- /// In this case, the first piece (`{}`) would be ArgumentImplicitlyIs with an index of 0. The
- /// total number of arguments is 3 and the number of named arguments is 2, so the start of named
- /// arguments is index 1. Therefore, the index of 0 is okay.
- ///
- /// The second piece (`{}`) would be ArgumentImplicitlyIs with an index of 1, which is the start
- /// of named arguments, and so we should add a lint to use the named argument `a`.
- ///
- /// The third piece (`{2}`) would be ArgumentIs with an index of 2, which is greater than the
- /// start of named arguments, and so we should add a lint to use the named argument `b`.
- ///
- /// This same check also works for width and precision formatting when either or both are
- /// CountIsParam, which contains an index into the arguments.
- fn maybe_add_positional_named_arg(
- &mut self,
- arg: Option<&FormatArg>,
- ty: PositionalNamedArgType,
- cur_piece: usize,
- inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
- has_formatting: bool,
- ) {
- if let Some(arg) = arg {
- if let Some(name) = arg.name {
- self.push(name, ty, cur_piece, inner_span_to_replace, has_formatting)
- }
- }
- }
- /// Construct a PositionalNamedArg struct and push it into the vec of positional
- /// named arguments.
- fn push(
- &mut self,
- arg_name: Ident,
- ty: PositionalNamedArgType,
- cur_piece: usize,
- inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
- has_formatting: bool,
- ) {
- // In FormatSpec, `precision_span` starts at the leading `.`, which we want to keep in
- // the lint suggestion, so increment `start` by 1 when `PositionalArgumentType` is
- // `Precision`.
- let inner_span_to_replace = if ty == PositionalNamedArgType::Precision {
- inner_span_to_replace
- .map(|is| rustc_parse_format::InnerSpan { start: is.start + 1, end: is.end })
- } else {
- inner_span_to_replace
- };
- self.positional_named_args.push(PositionalNamedArg {
- ty,
- cur_piece,
- inner_span_to_replace,
- replacement: arg_name.name,
- positional_named_arg_span: arg_name.span,
- has_formatting,
- });
- }
-}
-
-struct Context<'a, 'b> {
- ecx: &'a mut ExtCtxt<'b>,
- /// The macro's call site. References to unstable formatting internals must
- /// use this span to pass the stability checker.
- macsp: Span,
- /// The span of the format string literal.
- fmtsp: Span,
-
- /// List of parsed argument expressions.
- /// Named expressions are resolved early, and are appended to the end of
- /// argument expressions.
- ///
- /// Example showing the various data structures in motion:
- ///
- /// * Original: `"{foo:o} {:o} {foo:x} {0:x} {1:o} {:x} {1:x} {0:o}"`
- /// * Implicit argument resolution: `"{foo:o} {0:o} {foo:x} {0:x} {1:o} {1:x} {1:x} {0:o}"`
- /// * Name resolution: `"{2:o} {0:o} {2:x} {0:x} {1:o} {1:x} {1:x} {0:o}"`
- /// * `arg_types` (in JSON): `[[0, 1, 0], [0, 1, 1], [0, 1]]`
- /// * `arg_unique_types` (in simplified JSON): `[["o", "x"], ["o", "x"], ["o", "x"]]`
- /// * `names` (in JSON): `{"foo": 2}`
- args: Vec<FormatArg>,
- /// The number of arguments that were added by implicit capturing.
- num_captured_args: usize,
- /// Placeholder slot numbers indexed by argument.
- arg_types: Vec<Vec<usize>>,
- /// Unique format specs seen for each argument.
- arg_unique_types: Vec<Vec<ArgumentType>>,
- /// Map from named arguments to their resolved indices.
- names: FxHashMap<Symbol, usize>,
-
- /// The latest consecutive literal strings, or empty if there weren't any.
- literal: String,
+mod ast;
+use ast::*;
- /// Collection of the compiled `rt::Argument` structures
- pieces: Vec<P<ast::Expr>>,
- /// Collection of string literals
- str_pieces: Vec<P<ast::Expr>>,
- /// Stays `true` if all formatting parameters are default (as in "{}{}").
- all_pieces_simple: bool,
+mod expand;
+use expand::expand_parsed_format_args;
- /// Mapping between positional argument references and indices into the
- /// final generated static argument array. We record the starting indices
- /// corresponding to each positional argument, and number of references
- /// consumed so far for each argument, to facilitate correct `Position`
- /// mapping in `build_piece`. In effect this can be seen as a "flattened"
- /// version of `arg_unique_types`.
- ///
- /// Again with the example described above in docstring for `args`:
- ///
- /// * `arg_index_map` (in JSON): `[[0, 1, 0], [2, 3, 3], [4, 5]]`
- arg_index_map: Vec<Vec<usize>>,
+// The format_args!() macro is expanded in three steps:
+// 1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax,
+// but doesn't parse the template (the literal) itself.
+// 2. Second, `make_format_args` will parse the template, the format options, resolve argument references,
+// produce diagnostics, and turn the whole thing into a `FormatArgs` structure.
+// 3. Finally, `expand_parsed_format_args` will turn that `FormatArgs` structure
+// into the expression that the macro expands to.
- /// Starting offset of count argument slots.
- count_args_index_offset: usize,
+// See format/ast.rs for the FormatArgs structure and glossary.
- /// Count argument slots and tracking data structures.
- /// Count arguments are separately tracked for de-duplication in case
- /// multiple references are made to one argument. For example, in this
- /// format string:
- ///
- /// * Original: `"{:.*} {:.foo$} {1:.*} {:.0$}"`
- /// * Implicit argument resolution: `"{1:.0$} {2:.foo$} {1:.3$} {4:.0$}"`
- /// * Name resolution: `"{1:.0$} {2:.5$} {1:.3$} {4:.0$}"`
- /// * `count_positions` (in JSON): `{0: 0, 5: 1, 3: 2}`
- /// * `count_args`: `vec![0, 5, 3]`
- count_args: Vec<usize>,
- /// Relative slot numbers for count arguments.
- count_positions: FxHashMap<usize, usize>,
- /// Number of count slots assigned.
- count_positions_count: usize,
-
- /// Current position of the implicit positional arg pointer, as if it
- /// still existed in this phase of processing.
- /// Used only for `all_pieces_simple` tracking in `build_piece`.
- curarg: usize,
- /// Current piece being evaluated, used for error reporting.
- curpiece: usize,
- /// Keep track of invalid references to positional arguments.
- invalid_refs: Vec<(usize, usize)>,
- /// Spans of all the formatting arguments, in order.
- arg_spans: Vec<Span>,
- /// All the formatting arguments that have formatting flags set, in order for diagnostics.
- arg_with_formatting: Vec<parse::FormatSpec<'a>>,
-
- /// Whether this format string came from a string literal, as opposed to a macro.
- is_literal: bool,
- unused_names_lint: PositionalNamedArgsLint,
-}
-
-pub struct FormatArg {
- expr: P<ast::Expr>,
- name: Option<Ident>,
+// Only used in parse_args and report_invalid_references,
+// to indicate how a referred argument was used.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum PositionUsedAs {
+ Placeholder(Option<Span>),
+ Precision,
+ Width,
}
+use PositionUsedAs::*;
/// Parses the arguments from the given list of tokens, returning the diagnostic
/// if there's a parse error so we can continue parsing other format!
@@ -274,15 +45,14 @@ pub struct FormatArg {
/// If parsing succeeds, the return value is:
///
/// ```text
-/// Some((fmtstr, parsed arguments, index map for named arguments))
+/// Ok((fmtstr, parsed arguments))
/// ```
fn parse_args<'a>(
ecx: &mut ExtCtxt<'a>,
sp: Span,
tts: TokenStream,
-) -> PResult<'a, (P<ast::Expr>, Vec<FormatArg>, FxHashMap<Symbol, usize>)> {
- let mut args = Vec::<FormatArg>::new();
- let mut names = FxHashMap::<Symbol, usize>::default();
+) -> PResult<'a, (P<Expr>, FormatArguments)> {
+ let mut args = FormatArguments::new();
let mut p = ecx.new_parser_from_tts(tts);
@@ -311,7 +81,6 @@ fn parse_args<'a>(
};
let mut first = true;
- let mut named = false;
while p.token != token::Eof {
if !p.eat(&token::Comma) {
@@ -343,879 +112,54 @@ fn parse_args<'a>(
} // accept trailing commas
match p.token.ident() {
Some((ident, _)) if p.look_ahead(1, |t| *t == token::Eq) => {
- named = true;
p.bump();
p.expect(&token::Eq)?;
- let e = p.parse_expr()?;
- if let Some(&prev) = names.get(&ident.name) {
- ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident))
- .span_label(args[prev].expr.span, "previously here")
- .span_label(e.span, "duplicate argument")
- .emit();
+ let expr = p.parse_expr()?;
+ if let Some((_, prev)) = args.by_name(ident.name) {
+ ecx.struct_span_err(
+ ident.span,
+ &format!("duplicate argument named `{}`", ident),
+ )
+ .span_label(prev.kind.ident().unwrap().span, "previously here")
+ .span_label(ident.span, "duplicate argument")
+ .emit();
continue;
}
-
- // Resolve names into slots early.
- // Since all the positional args are already seen at this point
- // if the input is valid, we can simply append to the positional
- // args. And remember the names.
- let slot = args.len();
- names.insert(ident.name, slot);
- args.push(FormatArg { expr: e, name: Some(ident) });
+ args.add(FormatArgument { kind: FormatArgumentKind::Named(ident), expr });
}
_ => {
- let e = p.parse_expr()?;
- if named {
+ let expr = p.parse_expr()?;
+ if !args.named_args().is_empty() {
let mut err = ecx.struct_span_err(
- e.span,
+ expr.span,
"positional arguments cannot follow named arguments",
);
- err.span_label(e.span, "positional arguments must be before named arguments");
- for &pos in names.values() {
- err.span_label(args[pos].expr.span, "named argument");
+ err.span_label(
+ expr.span,
+ "positional arguments must be before named arguments",
+ );
+ for arg in args.named_args() {
+ if let Some(name) = arg.kind.ident() {
+ err.span_label(name.span.to(arg.expr.span), "named argument");
+ }
}
err.emit();
}
- args.push(FormatArg { expr: e, name: None });
+ args.add(FormatArgument { kind: FormatArgumentKind::Normal, expr });
}
}
}
- Ok((fmtstr, args, names))
+ Ok((fmtstr, args))
}
-impl<'a, 'b> Context<'a, 'b> {
- /// The number of arguments that were explicitly given.
- fn num_args(&self) -> usize {
- self.args.len() - self.num_captured_args
- }
-
- fn resolve_name_inplace(&mut self, p: &mut parse::Piece<'_>) {
- // NOTE: the `unwrap_or` branch is needed in case of invalid format
- // arguments, e.g., `format_args!("{foo}")`.
- let lookup = |s: &str| self.names.get(&Symbol::intern(s)).copied().unwrap_or(0);
-
- match *p {
- parse::String(_) => {}
- parse::NextArgument(ref mut arg) => {
- if let parse::ArgumentNamed(s) = arg.position {
- arg.position = parse::ArgumentIs(lookup(s));
- }
- if let parse::CountIsName(s, _) = arg.format.width {
- arg.format.width = parse::CountIsParam(lookup(s));
- }
- if let parse::CountIsName(s, _) = arg.format.precision {
- arg.format.precision = parse::CountIsParam(lookup(s));
- }
- }
- }
- }
-
- /// Verifies one piece of a parse string, and remembers it if valid.
- /// All errors are not emitted as fatal so we can continue giving errors
- /// about this and possibly other format strings.
- fn verify_piece(&mut self, p: &parse::Piece<'a>) {
- match *p {
- parse::String(..) => {}
- parse::NextArgument(ref arg) => {
- // width/precision first, if they have implicit positional
- // parameters it makes more sense to consume them first.
- self.verify_count(
- arg.format.width,
- &arg.format.width_span,
- PositionalNamedArgType::Width,
- );
- self.verify_count(
- arg.format.precision,
- &arg.format.precision_span,
- PositionalNamedArgType::Precision,
- );
-
- let has_precision = arg.format.precision != Count::CountImplied;
- let has_width = arg.format.width != Count::CountImplied;
-
- if has_precision || has_width {
- // push before named params are resolved to aid diagnostics
- self.arg_with_formatting.push(arg.format);
- }
-
- // argument second, if it's an implicit positional parameter
- // it's written second, so it should come after width/precision.
- let pos = match arg.position {
- parse::ArgumentIs(i) => {
- self.unused_names_lint.maybe_add_positional_named_arg(
- self.args.get(i),
- PositionalNamedArgType::Arg,
- self.curpiece,
- Some(arg.position_span),
- has_precision || has_width,
- );
-
- Exact(i)
- }
- parse::ArgumentImplicitlyIs(i) => {
- self.unused_names_lint.maybe_add_positional_named_arg(
- self.args.get(i),
- PositionalNamedArgType::Arg,
- self.curpiece,
- None,
- has_precision || has_width,
- );
- Exact(i)
- }
- parse::ArgumentNamed(s) => {
- let symbol = Symbol::intern(s);
- let span = arg.position_span;
- Named(symbol, InnerSpan::new(span.start, span.end))
- }
- };
-
- let ty = Placeholder(match arg.format.ty {
- "" => "Display",
- "?" => "Debug",
- "e" => "LowerExp",
- "E" => "UpperExp",
- "o" => "Octal",
- "p" => "Pointer",
- "b" => "Binary",
- "x" => "LowerHex",
- "X" => "UpperHex",
- _ => {
- let fmtsp = self.fmtsp;
- let sp = arg
- .format
- .ty_span
- .map(|sp| fmtsp.from_inner(InnerSpan::new(sp.start, sp.end)));
- let mut err = self.ecx.struct_span_err(
- sp.unwrap_or(fmtsp),
- &format!("unknown format trait `{}`", arg.format.ty),
- );
- err.note(
- "the only appropriate formatting traits are:\n\
- - ``, which uses the `Display` trait\n\
- - `?`, which uses the `Debug` trait\n\
- - `e`, which uses the `LowerExp` trait\n\
- - `E`, which uses the `UpperExp` trait\n\
- - `o`, which uses the `Octal` trait\n\
- - `p`, which uses the `Pointer` trait\n\
- - `b`, which uses the `Binary` trait\n\
- - `x`, which uses the `LowerHex` trait\n\
- - `X`, which uses the `UpperHex` trait",
- );
- if let Some(sp) = sp {
- for (fmt, name) in &[
- ("", "Display"),
- ("?", "Debug"),
- ("e", "LowerExp"),
- ("E", "UpperExp"),
- ("o", "Octal"),
- ("p", "Pointer"),
- ("b", "Binary"),
- ("x", "LowerHex"),
- ("X", "UpperHex"),
- ] {
- // FIXME: rustfix (`run-rustfix`) fails to apply suggestions.
- // > "Cannot replace slice of data that was already replaced"
- err.tool_only_span_suggestion(
- sp,
- &format!("use the `{}` trait", name),
- *fmt,
- Applicability::MaybeIncorrect,
- );
- }
- }
- err.emit();
- "<invalid>"
- }
- });
- self.verify_arg_type(pos, ty);
- self.curpiece += 1;
- }
- }
- }
-
- fn verify_count(
- &mut self,
- c: parse::Count<'_>,
- inner_span: &Option<rustc_parse_format::InnerSpan>,
- named_arg_type: PositionalNamedArgType,
- ) {
- match c {
- parse::CountImplied | parse::CountIs(..) => {}
- parse::CountIsParam(i) | parse::CountIsStar(i) => {
- self.unused_names_lint.maybe_add_positional_named_arg(
- self.args.get(i),
- named_arg_type,
- self.curpiece,
- *inner_span,
- true,
- );
- self.verify_arg_type(Exact(i), Count);
- }
- parse::CountIsName(s, span) => {
- self.verify_arg_type(
- Named(Symbol::intern(s), InnerSpan::new(span.start, span.end)),
- Count,
- );
- }
- }
- }
-
- fn describe_num_args(&self) -> Cow<'_, str> {
- match self.num_args() {
- 0 => "no arguments were given".into(),
- 1 => "there is 1 argument".into(),
- x => format!("there are {} arguments", x).into(),
- }
- }
-
- /// Handle invalid references to positional arguments. Output different
- /// errors for the case where all arguments are positional and for when
- /// there are named arguments or numbered positional arguments in the
- /// format string.
- fn report_invalid_references(&self, numbered_position_args: bool) {
- let mut e;
- let sp = if !self.arg_spans.is_empty() {
- // Point at the formatting arguments.
- MultiSpan::from_spans(self.arg_spans.clone())
- } else {
- MultiSpan::from_span(self.fmtsp)
- };
- let refs =
- self.invalid_refs.iter().map(|(r, pos)| (r.to_string(), self.arg_spans.get(*pos)));
-
- let mut zero_based_note = false;
-
- let count = self.pieces.len()
- + self
- .arg_with_formatting
- .iter()
- .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_)))
- .count();
- if self.names.is_empty() && !numbered_position_args && count != self.num_args() {
- e = self.ecx.struct_span_err(
- sp,
- &format!(
- "{} positional argument{} in format string, but {}",
- count,
- pluralize!(count),
- self.describe_num_args(),
- ),
- );
- for arg in &self.args {
- // Point at the arguments that will be formatted.
- e.span_label(arg.expr.span, "");
- }
- } else {
- let (mut refs, spans): (Vec<_>, Vec<_>) = refs.unzip();
- // Avoid `invalid reference to positional arguments 7 and 7 (there is 1 argument)`
- // for `println!("{7:7$}", 1);`
- refs.sort();
- refs.dedup();
- let spans: Vec<_> = spans.into_iter().filter_map(|sp| sp.copied()).collect();
- let sp = if self.arg_spans.is_empty() || spans.is_empty() {
- MultiSpan::from_span(self.fmtsp)
- } else {
- MultiSpan::from_spans(spans)
- };
- let arg_list = if refs.len() == 1 {
- format!("argument {}", refs[0])
- } else {
- let reg = refs.pop().unwrap();
- format!("arguments {head} and {tail}", head = refs.join(", "), tail = reg)
- };
-
- e = self.ecx.struct_span_err(
- sp,
- &format!(
- "invalid reference to positional {} ({})",
- arg_list,
- self.describe_num_args()
- ),
- );
- zero_based_note = true;
- };
-
- for fmt in &self.arg_with_formatting {
- if let Some(span) = fmt.precision_span {
- let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
- match fmt.precision {
- parse::CountIsParam(pos) if pos >= self.num_args() => {
- e.span_label(
- span,
- &format!(
- "this precision flag expects an `usize` argument at position {}, \
- but {}",
- pos,
- self.describe_num_args(),
- ),
- );
- zero_based_note = true;
- }
- parse::CountIsStar(pos) => {
- let count = self.pieces.len()
- + self
- .arg_with_formatting
- .iter()
- .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_)))
- .count();
- e.span_label(
- span,
- &format!(
- "this precision flag adds an extra required argument at position {}, \
- which is why there {} expected",
- pos,
- if count == 1 {
- "is 1 argument".to_string()
- } else {
- format!("are {} arguments", count)
- },
- ),
- );
- if let Some(arg) = self.args.get(pos) {
- e.span_label(
- arg.expr.span,
- "this parameter corresponds to the precision flag",
- );
- }
- zero_based_note = true;
- }
- _ => {}
- }
- }
- if let Some(span) = fmt.width_span {
- let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
- match fmt.width {
- parse::CountIsParam(pos) if pos >= self.num_args() => {
- e.span_label(
- span,
- &format!(
- "this width flag expects an `usize` argument at position {}, \
- but {}",
- pos,
- self.describe_num_args(),
- ),
- );
- zero_based_note = true;
- }
- _ => {}
- }
- }
- }
- if zero_based_note {
- e.note("positional arguments are zero-based");
- }
- if !self.arg_with_formatting.is_empty() {
- e.note(
- "for information about formatting flags, visit \
- https://doc.rust-lang.org/std/fmt/index.html",
- );
- }
-
- e.emit();
- }
-
- /// Actually verifies and tracks a given format placeholder
- /// (a.k.a. argument).
- fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
- if let Exact(arg) = arg {
- if arg >= self.num_args() {
- self.invalid_refs.push((arg, self.curpiece));
- return;
- }
- }
-
- match arg {
- Exact(arg) | Capture(arg) => {
- match ty {
- Placeholder(_) => {
- // record every (position, type) combination only once
- let seen_ty = &mut self.arg_unique_types[arg];
- let i = seen_ty.iter().position(|x| *x == ty).unwrap_or_else(|| {
- let i = seen_ty.len();
- seen_ty.push(ty);
- i
- });
- self.arg_types[arg].push(i);
- }
- Count => {
- if let Entry::Vacant(e) = self.count_positions.entry(arg) {
- let i = self.count_positions_count;
- e.insert(i);
- self.count_args.push(arg);
- self.count_positions_count += 1;
- }
- }
- }
- }
-
- Named(name, span) => {
- match self.names.get(&name) {
- Some(&idx) => {
- // Treat as positional arg.
- self.verify_arg_type(Capture(idx), ty)
- }
- None => {
- // For the moment capturing variables from format strings expanded from macros is
- // disabled (see RFC #2795)
- if self.is_literal {
- // Treat this name as a variable to capture from the surrounding scope
- let idx = self.args.len();
- self.arg_types.push(Vec::new());
- self.arg_unique_types.push(Vec::new());
- let span = if self.is_literal {
- self.fmtsp.from_inner(span)
- } else {
- self.fmtsp
- };
- self.num_captured_args += 1;
- self.args.push(FormatArg {
- expr: self.ecx.expr_ident(span, Ident::new(name, span)),
- name: Some(Ident::new(name, span)),
- });
- self.names.insert(name, idx);
- self.verify_arg_type(Capture(idx), ty)
- } else {
- let msg = format!("there is no argument named `{}`", name);
- let sp = if self.is_literal {
- self.fmtsp.from_inner(span)
- } else {
- self.fmtsp
- };
- let mut err = self.ecx.struct_span_err(sp, &msg);
-
- err.note(&format!(
- "did you intend to capture a variable `{}` from \
- the surrounding scope?",
- name
- ));
- err.note(
- "to avoid ambiguity, `format_args!` cannot capture variables \
- when the format string is expanded from a macro",
- );
-
- err.emit();
- }
- }
- }
- }
- }
- }
-
- /// Builds the mapping between format placeholders and argument objects.
- fn build_index_map(&mut self) {
- // NOTE: Keep the ordering the same as `into_expr`'s expansion would do!
- let args_len = self.args.len();
- self.arg_index_map.reserve(args_len);
-
- let mut sofar = 0usize;
-
- // Map the arguments
- for i in 0..args_len {
- let arg_types = &self.arg_types[i];
- let arg_offsets = arg_types.iter().map(|offset| sofar + *offset).collect::<Vec<_>>();
- self.arg_index_map.push(arg_offsets);
- sofar += self.arg_unique_types[i].len();
- }
-
- // Record starting index for counts, which appear just after arguments
- self.count_args_index_offset = sofar;
- }
-
- fn rtpath(ecx: &ExtCtxt<'_>, s: Symbol) -> Vec<Ident> {
- ecx.std_path(&[sym::fmt, sym::rt, sym::v1, s])
- }
-
- fn build_count(&self, c: parse::Count<'_>) -> P<ast::Expr> {
- let sp = self.macsp;
- let count = |c, arg| {
- let mut path = Context::rtpath(self.ecx, sym::Count);
- path.push(Ident::new(c, sp));
- match arg {
- Some(arg) => self.ecx.expr_call_global(sp, path, vec![arg]),
- None => self.ecx.expr_path(self.ecx.path_global(sp, path)),
- }
- };
- match c {
- parse::CountIs(i) => count(sym::Is, Some(self.ecx.expr_usize(sp, i))),
- parse::CountIsParam(i) | parse::CountIsStar(i) => {
- // This needs mapping too, as `i` is referring to a macro
- // argument. If `i` is not found in `count_positions` then
- // the error had already been emitted elsewhere.
- let i = self.count_positions.get(&i).cloned().unwrap_or(0)
- + self.count_args_index_offset;
- count(sym::Param, Some(self.ecx.expr_usize(sp, i)))
- }
- parse::CountImplied => count(sym::Implied, None),
- // should never be the case, names are already resolved
- parse::CountIsName(..) => panic!("should never happen"),
- }
- }
-
- /// Build a literal expression from the accumulated string literals
- fn build_literal_string(&mut self) -> P<ast::Expr> {
- let sp = self.fmtsp;
- let s = Symbol::intern(&self.literal);
- self.literal.clear();
- self.ecx.expr_str(sp, s)
- }
-
- /// Builds a static `rt::Argument` from a `parse::Piece` or append
- /// to the `literal` string.
- fn build_piece(
- &mut self,
- piece: &parse::Piece<'a>,
- arg_index_consumed: &mut Vec<usize>,
- ) -> Option<P<ast::Expr>> {
- let sp = self.macsp;
- match *piece {
- parse::String(s) => {
- self.literal.push_str(s);
- None
- }
- parse::NextArgument(ref arg) => {
- // Build the position
- let pos = {
- match arg.position {
- parse::ArgumentIs(i, ..) | parse::ArgumentImplicitlyIs(i) => {
- // Map to index in final generated argument array
- // in case of multiple types specified
- let arg_idx = match arg_index_consumed.get_mut(i) {
- None => 0, // error already emitted elsewhere
- Some(offset) => {
- let idx_map = &self.arg_index_map[i];
- // unwrap_or branch: error already emitted elsewhere
- let arg_idx = *idx_map.get(*offset).unwrap_or(&0);
- *offset += 1;
- arg_idx
- }
- };
- self.ecx.expr_usize(sp, arg_idx)
- }
-
- // should never be the case, because names are already
- // resolved.
- parse::ArgumentNamed(..) => panic!("should never happen"),
- }
- };
-
- let simple_arg = parse::Argument {
- position: {
- // We don't have ArgumentNext any more, so we have to
- // track the current argument ourselves.
- let i = self.curarg;
- self.curarg += 1;
- parse::ArgumentIs(i)
- },
- position_span: arg.position_span,
- format: parse::FormatSpec {
- fill: None,
- align: parse::AlignUnknown,
- flags: 0,
- precision: parse::CountImplied,
- precision_span: arg.format.precision_span,
- width: parse::CountImplied,
- width_span: arg.format.width_span,
- ty: arg.format.ty,
- ty_span: arg.format.ty_span,
- },
- };
-
- let fill = arg.format.fill.unwrap_or(' ');
- let pos_simple = arg.position.index() == simple_arg.position.index();
-
- if !pos_simple || arg.format != simple_arg.format {
- self.all_pieces_simple = false;
- }
-
- // Build the format
- let fill = self.ecx.expr_char(sp, fill);
- let align = |name| {
- let mut p = Context::rtpath(self.ecx, sym::Alignment);
- p.push(Ident::new(name, sp));
- self.ecx.path_global(sp, p)
- };
- let align = match arg.format.align {
- parse::AlignLeft => align(sym::Left),
- parse::AlignRight => align(sym::Right),
- parse::AlignCenter => align(sym::Center),
- parse::AlignUnknown => align(sym::Unknown),
- };
- let align = self.ecx.expr_path(align);
- let flags = self.ecx.expr_u32(sp, arg.format.flags);
- let prec = self.build_count(arg.format.precision);
- let width = self.build_count(arg.format.width);
- let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, sym::FormatSpec));
- let fmt = self.ecx.expr_struct(
- sp,
- path,
- vec![
- self.ecx.field_imm(sp, Ident::new(sym::fill, sp), fill),
- self.ecx.field_imm(sp, Ident::new(sym::align, sp), align),
- self.ecx.field_imm(sp, Ident::new(sym::flags, sp), flags),
- self.ecx.field_imm(sp, Ident::new(sym::precision, sp), prec),
- self.ecx.field_imm(sp, Ident::new(sym::width, sp), width),
- ],
- );
-
- let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, sym::Argument));
- Some(self.ecx.expr_struct(
- sp,
- path,
- vec![
- self.ecx.field_imm(sp, Ident::new(sym::position, sp), pos),
- self.ecx.field_imm(sp, Ident::new(sym::format, sp), fmt),
- ],
- ))
- }
- }
- }
-
- /// Actually builds the expression which the format_args! block will be
- /// expanded to.
- fn into_expr(self) -> P<ast::Expr> {
- let mut original_args = self.args;
- let mut fmt_args = Vec::with_capacity(
- self.arg_unique_types.iter().map(|v| v.len()).sum::<usize>() + self.count_args.len(),
- );
-
- // First, build up the static array which will become our precompiled
- // format "string"
- let pieces = self.ecx.expr_array_ref(self.fmtsp, self.str_pieces);
-
- // We need to construct a &[ArgumentV1] to pass into the fmt::Arguments
- // constructor. In general the expressions in this slice might be
- // permuted from their order in original_args (such as in the case of
- // "{1} {0}"), or may have multiple entries referring to the same
- // element of original_args ("{0} {0}").
- //
- // The following vector has one item per element of our output slice,
- // identifying the index of which element of original_args it's passing,
- // and that argument's type.
- let mut fmt_arg_index_and_ty = SmallVec::<[(usize, &ArgumentType); 8]>::new();
- for (i, unique_types) in self.arg_unique_types.iter().enumerate() {
- fmt_arg_index_and_ty.extend(unique_types.iter().map(|ty| (i, ty)));
- }
- fmt_arg_index_and_ty.extend(self.count_args.iter().map(|&i| (i, &Count)));
-
- // Figure out whether there are permuted or repeated elements. If not,
- // we can generate simpler code.
- //
- // The sequence has no indices out of order or repeated if: for every
- // adjacent pair of elements, the first one's index is less than the
- // second one's index.
- let nicely_ordered =
- fmt_arg_index_and_ty.array_windows().all(|[(i, _i_ty), (j, _j_ty)]| i < j);
-
- // We want to emit:
- //
- // [ArgumentV1::new(&$arg0, …), ArgumentV1::new(&$arg1, …), …]
- //
- // However, it's only legal to do so if $arg0, $arg1, … were written in
- // exactly that order by the programmer. When arguments are permuted, we
- // want them evaluated in the order written by the programmer, not in
- // the order provided to fmt::Arguments. When arguments are repeated, we
- // want the expression evaluated only once.
- //
- // Further, if any arg _after the first one_ contains a yield point such
- // as `await` or `yield`, the above short form is inconvenient for the
- // caller because it would keep a temporary of type ArgumentV1 alive
- // across the yield point. ArgumentV1 can't implement Send since it
- // holds a type-erased arbitrary type.
- //
- // Thus in the not nicely ordered case, and in the yielding case, we
- // emit the following instead:
- //
- // match (&$arg0, &$arg1, …) {
- // args => [ArgumentV1::new(args.$i, …), ArgumentV1::new(args.$j, …), …]
- // }
- //
- // for the sequence of indices $i, $j, … governed by fmt_arg_index_and_ty.
- // This more verbose representation ensures that all arguments are
- // evaluated a single time each, in the order written by the programmer,
- // and that the surrounding future/generator (if any) is Send whenever
- // possible.
- let no_need_for_match = nicely_ordered
- && !original_args.iter().skip(1).any(|arg| may_contain_yield_point(&arg.expr));
-
- for (arg_index, arg_ty) in fmt_arg_index_and_ty {
- let e = &mut original_args[arg_index].expr;
- let span = e.span;
- let arg = if no_need_for_match {
- let expansion_span = e.span.with_ctxt(self.macsp.ctxt());
- // The indices are strictly ordered so e has not been taken yet.
- self.ecx.expr_addr_of(expansion_span, P(e.take()))
- } else {
- let def_site = self.ecx.with_def_site_ctxt(span);
- let args_tuple = self.ecx.expr_ident(def_site, Ident::new(sym::args, def_site));
- let member = Ident::new(sym::integer(arg_index), def_site);
- self.ecx.expr(def_site, ast::ExprKind::Field(args_tuple, member))
- };
- fmt_args.push(Context::format_arg(self.ecx, self.macsp, span, arg_ty, arg));
- }
-
- let args_array = self.ecx.expr_array(self.macsp, fmt_args);
- let args_slice = self.ecx.expr_addr_of(
- self.macsp,
- if no_need_for_match {
- args_array
- } else {
- // In the !no_need_for_match case, none of the exprs were moved
- // away in the previous loop.
- //
- // This uses the arg span for `&arg` so that borrowck errors
- // point to the specific expression passed to the macro (the
- // span is otherwise unavailable in the MIR used by borrowck).
- let heads = original_args
- .into_iter()
- .map(|arg| {
- self.ecx.expr_addr_of(arg.expr.span.with_ctxt(self.macsp.ctxt()), arg.expr)
- })
- .collect();
-
- let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::args, self.macsp));
- let arm = self.ecx.arm(self.macsp, pat, args_array);
- let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads));
- self.ecx.expr_match(self.macsp, head, vec![arm])
- },
- );
-
- // Now create the fmt::Arguments struct with all our locals we created.
- let (fn_name, fn_args) = if self.all_pieces_simple {
- ("new_v1", vec![pieces, args_slice])
- } else {
- // Build up the static array which will store our precompiled
- // nonstandard placeholders, if there are any.
- let fmt = self.ecx.expr_array_ref(self.macsp, self.pieces);
-
- let path = self.ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]);
- let unsafe_arg = self.ecx.expr_call_global(self.macsp, path, Vec::new());
- let unsafe_expr = self.ecx.expr_block(P(ast::Block {
- stmts: vec![self.ecx.stmt_expr(unsafe_arg)],
- id: ast::DUMMY_NODE_ID,
- rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
- span: self.macsp,
- tokens: None,
- could_be_bare_literal: false,
- }));
-
- ("new_v1_formatted", vec![pieces, args_slice, fmt, unsafe_expr])
- };
-
- let path = self.ecx.std_path(&[sym::fmt, sym::Arguments, Symbol::intern(fn_name)]);
- self.ecx.expr_call_global(self.macsp, path, fn_args)
- }
-
- fn format_arg(
- ecx: &ExtCtxt<'_>,
- macsp: Span,
- mut sp: Span,
- ty: &ArgumentType,
- arg: P<ast::Expr>,
- ) -> P<ast::Expr> {
- sp = ecx.with_def_site_ctxt(sp);
- let trait_ = match *ty {
- Placeholder(trait_) if trait_ == "<invalid>" => return DummyResult::raw_expr(sp, true),
- Placeholder(trait_) => trait_,
- Count => {
- let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, sym::from_usize]);
- return ecx.expr_call_global(macsp, path, vec![arg]);
- }
- };
- let new_fn_name = match trait_ {
- "Display" => "new_display",
- "Debug" => "new_debug",
- "LowerExp" => "new_lower_exp",
- "UpperExp" => "new_upper_exp",
- "Octal" => "new_octal",
- "Pointer" => "new_pointer",
- "Binary" => "new_binary",
- "LowerHex" => "new_lower_hex",
- "UpperHex" => "new_upper_hex",
- _ => unreachable!(),
- };
-
- let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, Symbol::intern(new_fn_name)]);
- ecx.expr_call_global(sp, path, vec![arg])
- }
-}
-
-fn expand_format_args_impl<'cx>(
- ecx: &'cx mut ExtCtxt<'_>,
- mut sp: Span,
- tts: TokenStream,
- nl: bool,
-) -> Box<dyn base::MacResult + 'cx> {
- sp = ecx.with_def_site_ctxt(sp);
- match parse_args(ecx, sp, tts) {
- Ok((efmt, args, names)) => {
- MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names, nl))
- }
- Err(mut err) => {
- err.emit();
- DummyResult::any(sp)
- }
- }
-}
-
-pub fn expand_format_args<'cx>(
- ecx: &'cx mut ExtCtxt<'_>,
- sp: Span,
- tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
- expand_format_args_impl(ecx, sp, tts, false)
-}
-
-pub fn expand_format_args_nl<'cx>(
- ecx: &'cx mut ExtCtxt<'_>,
- sp: Span,
- tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
- expand_format_args_impl(ecx, sp, tts, true)
-}
-
-fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>) {
- for named_arg in &cx.unused_names_lint.positional_named_args {
- let (position_sp_to_replace, position_sp_for_msg) = named_arg.get_positional_arg_spans(cx);
-
- let msg = format!("named argument `{}` is not used by name", named_arg.replacement);
-
- cx.ecx.buffered_early_lint.push(BufferedEarlyLint {
- span: MultiSpan::from_span(named_arg.positional_named_arg_span),
- msg: msg.into(),
- node_id: ast::CRATE_NODE_ID,
- lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
- diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally {
- position_sp_to_replace,
- position_sp_for_msg,
- named_arg_sp: named_arg.positional_named_arg_span,
- named_arg_name: named_arg.replacement.to_string(),
- is_formatting_arg: named_arg.ty != PositionalNamedArgType::Arg,
- },
- });
- }
-}
-
-/// Take the various parts of `format_args!(efmt, args..., name=names...)`
-/// and construct the appropriate formatting expression.
-pub fn expand_preparsed_format_args(
+pub fn make_format_args(
ecx: &mut ExtCtxt<'_>,
- sp: Span,
- efmt: P<ast::Expr>,
- args: Vec<FormatArg>,
- names: FxHashMap<Symbol, usize>,
+ efmt: P<Expr>,
+ mut args: FormatArguments,
append_newline: bool,
-) -> P<ast::Expr> {
- // NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because
- // `ArgumentType` does not derive `Clone`.
- let arg_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect();
- let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect();
-
- let mut macsp = ecx.call_site();
- macsp = ecx.with_def_site_ctxt(macsp);
-
+) -> Result<FormatArgs, ()> {
let msg = "format argument must be a string literal";
- let fmt_sp = efmt.span;
- let efmt_kind_is_lit: bool = matches!(efmt.kind, ast::ExprKind::Lit(_));
+ let unexpanded_fmt_span = efmt.span;
let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt, msg) {
Ok(mut fmt) if append_newline => {
fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
@@ -1224,13 +168,13 @@ pub fn expand_preparsed_format_args(
Ok(fmt) => fmt,
Err(err) => {
if let Some((mut err, suggested)) = err {
- let sugg_fmt = match args.len() {
+ let sugg_fmt = match args.explicit_args().len() {
0 => "{}".to_string(),
- _ => format!("{}{{}}", "{} ".repeat(args.len())),
+ _ => format!("{}{{}}", "{} ".repeat(args.explicit_args().len())),
};
if !suggested {
err.span_suggestion(
- fmt_sp.shrink_to_lo(),
+ unexpanded_fmt_span.shrink_to_lo(),
"you might be missing a string literal to format with",
format!("\"{}\", ", sugg_fmt),
Applicability::MaybeIncorrect,
@@ -1238,17 +182,17 @@ pub fn expand_preparsed_format_args(
}
err.emit();
}
- return DummyResult::raw_expr(sp, true);
+ return Err(());
}
};
let str_style = match fmt_style {
- ast::StrStyle::Cooked => None,
- ast::StrStyle::Raw(raw) => Some(raw as usize),
+ rustc_ast::StrStyle::Cooked => None,
+ rustc_ast::StrStyle::Raw(raw) => Some(raw as usize),
};
let fmt_str = fmt_str.as_str(); // for the suggestions below
- let fmt_snippet = ecx.source_map().span_to_snippet(fmt_sp).ok();
+ let fmt_snippet = ecx.source_map().span_to_snippet(unexpanded_fmt_span).ok();
let mut parser = parse::Parser::new(
fmt_str,
str_style,
@@ -1257,18 +201,20 @@ pub fn expand_preparsed_format_args(
parse::ParseMode::Format,
);
- let mut unverified_pieces = Vec::new();
+ let mut pieces = Vec::new();
while let Some(piece) = parser.next() {
if !parser.errors.is_empty() {
break;
} else {
- unverified_pieces.push(piece);
+ pieces.push(piece);
}
}
+ let is_literal = parser.is_literal;
+
if !parser.errors.is_empty() {
let err = parser.errors.remove(0);
- let sp = if efmt_kind_is_lit {
+ let sp = if is_literal {
fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end))
} else {
// The format string could be another macro invocation, e.g.:
@@ -1286,25 +232,21 @@ pub fn expand_preparsed_format_args(
if let Some(note) = err.note {
e.note(&note);
}
- if let Some((label, span)) = err.secondary_label {
- if efmt_kind_is_lit {
- e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label);
- }
+ if let Some((label, span)) = err.secondary_label && is_literal {
+ e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label);
}
if err.should_be_replaced_with_positional_argument {
let captured_arg_span =
fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
- let n_positional_args =
- args.iter().rposition(|arg| arg.name.is_none()).map_or(0, |i| i + 1);
if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) {
- let span = match args[..n_positional_args].last() {
+ let span = match args.unnamed_args().last() {
Some(arg) => arg.expr.span,
- None => fmt_sp,
+ None => fmt_span,
};
e.multipart_suggestion_verbose(
"consider using a positional formatting argument instead",
vec![
- (captured_arg_span, n_positional_args.to_string()),
+ (captured_arg_span, args.unnamed_args().len().to_string()),
(span.shrink_to_hi(), format!(", {}", arg)),
],
Applicability::MachineApplicable,
@@ -1312,241 +254,626 @@ pub fn expand_preparsed_format_args(
}
}
e.emit();
- return DummyResult::raw_expr(sp, true);
+ return Err(());
}
- let arg_spans = parser
- .arg_places
- .iter()
- .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
- .collect();
+ let to_span = |inner_span: rustc_parse_format::InnerSpan| {
+ is_literal.then(|| {
+ fmt_span.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end })
+ })
+ };
+
+ let mut used = vec![false; args.explicit_args().len()];
+ let mut invalid_refs = Vec::new();
+ let mut numeric_refences_to_named_arg = Vec::new();
- let mut cx = Context {
- ecx,
- args,
- num_captured_args: 0,
- arg_types,
- arg_unique_types,
- names,
- curarg: 0,
- curpiece: 0,
- arg_index_map: Vec::new(),
- count_args: Vec::new(),
- count_positions: FxHashMap::default(),
- count_positions_count: 0,
- count_args_index_offset: 0,
- literal: String::new(),
- pieces: Vec::with_capacity(unverified_pieces.len()),
- str_pieces: Vec::with_capacity(unverified_pieces.len()),
- all_pieces_simple: true,
- macsp,
- fmtsp: fmt_span,
- invalid_refs: Vec::new(),
- arg_spans,
- arg_with_formatting: Vec::new(),
- is_literal: parser.is_literal,
- unused_names_lint: PositionalNamedArgsLint { positional_named_args: vec![] },
+ enum ArgRef<'a> {
+ Index(usize),
+ Name(&'a str, Option<Span>),
+ }
+ use ArgRef::*;
+
+ let mut lookup_arg = |arg: ArgRef<'_>,
+ span: Option<Span>,
+ used_as: PositionUsedAs,
+ kind: FormatArgPositionKind|
+ -> FormatArgPosition {
+ let index = match arg {
+ Index(index) => {
+ if let Some(arg) = args.by_index(index) {
+ used[index] = true;
+ if arg.kind.ident().is_some() {
+ // This was a named argument, but it was used as a positional argument.
+ numeric_refences_to_named_arg.push((index, span, used_as));
+ }
+ Ok(index)
+ } else {
+ // Doesn't exist as an explicit argument.
+ invalid_refs.push((index, span, used_as, kind));
+ Err(index)
+ }
+ }
+ Name(name, span) => {
+ let name = Symbol::intern(name);
+ if let Some((index, _)) = args.by_name(name) {
+ // Name found in `args`, so we resolve it to its index.
+ if index < args.explicit_args().len() {
+ // Mark it as used, if it was an explicit argument.
+ used[index] = true;
+ }
+ Ok(index)
+ } else {
+ // Name not found in `args`, so we add it as an implicitly captured argument.
+ let span = span.unwrap_or(fmt_span);
+ let ident = Ident::new(name, span);
+ let expr = if is_literal {
+ ecx.expr_ident(span, ident)
+ } else {
+ // For the moment capturing variables from format strings expanded from macros is
+ // disabled (see RFC #2795)
+ ecx.struct_span_err(span, &format!("there is no argument named `{name}`"))
+ .note(format!("did you intend to capture a variable `{name}` from the surrounding scope?"))
+ .note("to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro")
+ .emit();
+ DummyResult::raw_expr(span, true)
+ };
+ Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr }))
+ }
+ }
+ };
+ FormatArgPosition { index, kind, span }
};
- // This needs to happen *after* the Parser has consumed all pieces to create all the spans
- let pieces = unverified_pieces
- .into_iter()
- .map(|mut piece| {
- cx.verify_piece(&piece);
- cx.resolve_name_inplace(&mut piece);
- piece
- })
- .collect::<Vec<_>>();
+ let mut template = Vec::new();
+ let mut unfinished_literal = String::new();
+ let mut placeholder_index = 0;
- let numbered_position_args = pieces.iter().any(|arg: &parse::Piece<'_>| match *arg {
- parse::String(_) => false,
- parse::NextArgument(arg) => matches!(arg.position, parse::Position::ArgumentIs(..)),
- });
+ for piece in pieces {
+ match piece {
+ parse::Piece::String(s) => {
+ unfinished_literal.push_str(s);
+ }
+ parse::Piece::NextArgument(parse::Argument { position, position_span, format }) => {
+ if !unfinished_literal.is_empty() {
+ template.push(FormatArgsPiece::Literal(Symbol::intern(&unfinished_literal)));
+ unfinished_literal.clear();
+ }
- cx.build_index_map();
+ let span = parser.arg_places.get(placeholder_index).and_then(|&s| to_span(s));
+ placeholder_index += 1;
+
+ let position_span = to_span(position_span);
+ let argument = match position {
+ parse::ArgumentImplicitlyIs(i) => lookup_arg(
+ Index(i),
+ position_span,
+ Placeholder(span),
+ FormatArgPositionKind::Implicit,
+ ),
+ parse::ArgumentIs(i) => lookup_arg(
+ Index(i),
+ position_span,
+ Placeholder(span),
+ FormatArgPositionKind::Number,
+ ),
+ parse::ArgumentNamed(name) => lookup_arg(
+ Name(name, position_span),
+ position_span,
+ Placeholder(span),
+ FormatArgPositionKind::Named,
+ ),
+ };
- let mut arg_index_consumed = vec![0usize; cx.arg_index_map.len()];
+ let alignment = match format.align {
+ parse::AlignUnknown => None,
+ parse::AlignLeft => Some(FormatAlignment::Left),
+ parse::AlignRight => Some(FormatAlignment::Right),
+ parse::AlignCenter => Some(FormatAlignment::Center),
+ };
- for piece in pieces {
- if let Some(piece) = cx.build_piece(&piece, &mut arg_index_consumed) {
- let s = cx.build_literal_string();
- cx.str_pieces.push(s);
- cx.pieces.push(piece);
+ let format_trait = match format.ty {
+ "" => FormatTrait::Display,
+ "?" => FormatTrait::Debug,
+ "e" => FormatTrait::LowerExp,
+ "E" => FormatTrait::UpperExp,
+ "o" => FormatTrait::Octal,
+ "p" => FormatTrait::Pointer,
+ "b" => FormatTrait::Binary,
+ "x" => FormatTrait::LowerHex,
+ "X" => FormatTrait::UpperHex,
+ _ => {
+ invalid_placeholder_type_error(ecx, format.ty, format.ty_span, fmt_span);
+ FormatTrait::Display
+ }
+ };
+
+ let precision_span = format.precision_span.and_then(to_span);
+ let precision = match format.precision {
+ parse::CountIs(n) => Some(FormatCount::Literal(n)),
+ parse::CountIsName(name, name_span) => Some(FormatCount::Argument(lookup_arg(
+ Name(name, to_span(name_span)),
+ precision_span,
+ Precision,
+ FormatArgPositionKind::Named,
+ ))),
+ parse::CountIsParam(i) => Some(FormatCount::Argument(lookup_arg(
+ Index(i),
+ precision_span,
+ Precision,
+ FormatArgPositionKind::Number,
+ ))),
+ parse::CountIsStar(i) => Some(FormatCount::Argument(lookup_arg(
+ Index(i),
+ precision_span,
+ Precision,
+ FormatArgPositionKind::Implicit,
+ ))),
+ parse::CountImplied => None,
+ };
+
+ let width_span = format.width_span.and_then(to_span);
+ let width = match format.width {
+ parse::CountIs(n) => Some(FormatCount::Literal(n)),
+ parse::CountIsName(name, name_span) => Some(FormatCount::Argument(lookup_arg(
+ Name(name, to_span(name_span)),
+ width_span,
+ Width,
+ FormatArgPositionKind::Named,
+ ))),
+ parse::CountIsParam(i) => Some(FormatCount::Argument(lookup_arg(
+ Index(i),
+ width_span,
+ Width,
+ FormatArgPositionKind::Number,
+ ))),
+ parse::CountIsStar(_) => unreachable!(),
+ parse::CountImplied => None,
+ };
+
+ template.push(FormatArgsPiece::Placeholder(FormatPlaceholder {
+ argument,
+ span,
+ format_trait,
+ format_options: FormatOptions {
+ fill: format.fill,
+ alignment,
+ flags: format.flags,
+ precision,
+ width,
+ },
+ }));
+ }
}
}
- if !cx.literal.is_empty() {
- let s = cx.build_literal_string();
- cx.str_pieces.push(s);
+ if !unfinished_literal.is_empty() {
+ template.push(FormatArgsPiece::Literal(Symbol::intern(&unfinished_literal)));
}
- if !cx.invalid_refs.is_empty() {
- cx.report_invalid_references(numbered_position_args);
+ if !invalid_refs.is_empty() {
+ report_invalid_references(ecx, &invalid_refs, &template, fmt_span, &args, parser);
}
- // Make sure that all arguments were used and all arguments have types.
- let errs = cx
- .arg_types
+ let unused = used
.iter()
.enumerate()
- .filter(|(i, ty)| ty.is_empty() && !cx.count_positions.contains_key(&i))
+ .filter(|&(_, used)| !used)
.map(|(i, _)| {
- let msg = if cx.args[i].name.is_some() {
+ let msg = if let FormatArgumentKind::Named(_) = args.explicit_args()[i].kind {
"named argument never used"
} else {
"argument never used"
};
- (cx.args[i].expr.span, msg)
+ (args.explicit_args()[i].expr.span, msg)
})
.collect::<Vec<_>>();
- let errs_len = errs.len();
- if !errs.is_empty() {
- let args_used = cx.arg_types.len() - errs_len;
- let args_unused = errs_len;
+ if !unused.is_empty() {
+ // If there's a lot of unused arguments,
+ // let's check if this format arguments looks like another syntax (printf / shell).
+ let detect_foreign_fmt = unused.len() > args.explicit_args().len() / 2;
+ report_missing_placeholders(ecx, unused, detect_foreign_fmt, str_style, fmt_str, fmt_span);
+ }
- let mut diag = {
- if let [(sp, msg)] = &errs[..] {
- let mut diag = cx.ecx.struct_span_err(*sp, *msg);
- diag.span_label(*sp, *msg);
- diag
- } else {
- let mut diag = cx.ecx.struct_span_err(
- errs.iter().map(|&(sp, _)| sp).collect::<Vec<Span>>(),
- "multiple unused formatting arguments",
- );
- diag.span_label(cx.fmtsp, "multiple missing formatting specifiers");
- for (sp, msg) in errs {
- diag.span_label(sp, msg);
+ // Only check for unused named argument names if there are no other errors to avoid causing
+ // too much noise in output errors, such as when a named argument is entirely unused.
+ if invalid_refs.is_empty() && ecx.sess.err_count() == 0 {
+ for &(index, span, used_as) in &numeric_refences_to_named_arg {
+ let (position_sp_to_replace, position_sp_for_msg) = match used_as {
+ Placeholder(pspan) => (span, pspan),
+ Precision => {
+ // Strip the leading `.` for precision.
+ let span = span.map(|span| span.with_lo(span.lo() + BytePos(1)));
+ (span, span)
}
- diag
- }
- };
+ Width => (span, span),
+ };
+ let arg_name = args.explicit_args()[index].kind.ident().unwrap();
+ ecx.buffered_early_lint.push(BufferedEarlyLint {
+ span: arg_name.span.into(),
+ msg: format!("named argument `{}` is not used by name", arg_name.name).into(),
+ node_id: rustc_ast::CRATE_NODE_ID,
+ lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
+ diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally {
+ position_sp_to_replace,
+ position_sp_for_msg,
+ named_arg_sp: arg_name.span,
+ named_arg_name: arg_name.name.to_string(),
+ is_formatting_arg: matches!(used_as, Width | Precision),
+ },
+ });
+ }
+ }
- // Used to ensure we only report translations for *one* kind of foreign format.
- let mut found_foreign = false;
- // Decide if we want to look for foreign formatting directives.
- if args_used < args_unused {
- use super::format_foreign as foreign;
+ Ok(FormatArgs { span: fmt_span, template, arguments: args })
+}
- // The set of foreign substitutions we've explained. This prevents spamming the user
- // with `%d should be written as {}` over and over again.
- let mut explained = FxHashSet::default();
+fn invalid_placeholder_type_error(
+ ecx: &ExtCtxt<'_>,
+ ty: &str,
+ ty_span: Option<rustc_parse_format::InnerSpan>,
+ fmt_span: Span,
+) {
+ let sp = ty_span.map(|sp| fmt_span.from_inner(InnerSpan::new(sp.start, sp.end)));
+ let mut err =
+ ecx.struct_span_err(sp.unwrap_or(fmt_span), &format!("unknown format trait `{}`", ty));
+ err.note(
+ "the only appropriate formatting traits are:\n\
+ - ``, which uses the `Display` trait\n\
+ - `?`, which uses the `Debug` trait\n\
+ - `e`, which uses the `LowerExp` trait\n\
+ - `E`, which uses the `UpperExp` trait\n\
+ - `o`, which uses the `Octal` trait\n\
+ - `p`, which uses the `Pointer` trait\n\
+ - `b`, which uses the `Binary` trait\n\
+ - `x`, which uses the `LowerHex` trait\n\
+ - `X`, which uses the `UpperHex` trait",
+ );
+ if let Some(sp) = sp {
+ for (fmt, name) in &[
+ ("", "Display"),
+ ("?", "Debug"),
+ ("e", "LowerExp"),
+ ("E", "UpperExp"),
+ ("o", "Octal"),
+ ("p", "Pointer"),
+ ("b", "Binary"),
+ ("x", "LowerHex"),
+ ("X", "UpperHex"),
+ ] {
+ err.tool_only_span_suggestion(
+ sp,
+ &format!("use the `{}` trait", name),
+ *fmt,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ err.emit();
+}
- macro_rules! check_foreign {
- ($kind:ident) => {{
- let mut show_doc_note = false;
+fn report_missing_placeholders(
+ ecx: &mut ExtCtxt<'_>,
+ unused: Vec<(Span, &str)>,
+ detect_foreign_fmt: bool,
+ str_style: Option<usize>,
+ fmt_str: &str,
+ fmt_span: Span,
+) {
+ let mut diag = if let &[(span, msg)] = &unused[..] {
+ let mut diag = ecx.struct_span_err(span, msg);
+ diag.span_label(span, msg);
+ diag
+ } else {
+ let mut diag = ecx.struct_span_err(
+ unused.iter().map(|&(sp, _)| sp).collect::<Vec<Span>>(),
+ "multiple unused formatting arguments",
+ );
+ diag.span_label(fmt_span, "multiple missing formatting specifiers");
+ for &(span, msg) in &unused {
+ diag.span_label(span, msg);
+ }
+ diag
+ };
- let mut suggestions = vec![];
- // account for `"` and account for raw strings `r#`
- let padding = str_style.map(|i| i + 2).unwrap_or(1);
- for sub in foreign::$kind::iter_subs(fmt_str, padding) {
- let (trn, success) = match sub.translate() {
- Ok(trn) => (trn, true),
- Err(Some(msg)) => (msg, false),
+ // Used to ensure we only report translations for *one* kind of foreign format.
+ let mut found_foreign = false;
+
+ // Decide if we want to look for foreign formatting directives.
+ if detect_foreign_fmt {
+ use super::format_foreign as foreign;
+
+ // The set of foreign substitutions we've explained. This prevents spamming the user
+ // with `%d should be written as {}` over and over again.
+ let mut explained = FxHashSet::default();
+
+ macro_rules! check_foreign {
+ ($kind:ident) => {{
+ let mut show_doc_note = false;
+
+ let mut suggestions = vec![];
+ // account for `"` and account for raw strings `r#`
+ let padding = str_style.map(|i| i + 2).unwrap_or(1);
+ for sub in foreign::$kind::iter_subs(fmt_str, padding) {
+ let (trn, success) = match sub.translate() {
+ Ok(trn) => (trn, true),
+ Err(Some(msg)) => (msg, false),
+
+ // If it has no translation, don't call it out specifically.
+ _ => continue,
+ };
+
+ let pos = sub.position();
+ let sub = String::from(sub.as_str());
+ if explained.contains(&sub) {
+ continue;
+ }
+ explained.insert(sub.clone());
- // If it has no translation, don't call it out specifically.
- _ => continue,
- };
+ if !found_foreign {
+ found_foreign = true;
+ show_doc_note = true;
+ }
- let pos = sub.position();
- let sub = String::from(sub.as_str());
- if explained.contains(&sub) {
- continue;
- }
- explained.insert(sub.clone());
+ if let Some(inner_sp) = pos {
+ let sp = fmt_span.from_inner(inner_sp);
- if !found_foreign {
- found_foreign = true;
- show_doc_note = true;
+ if success {
+ suggestions.push((sp, trn));
+ } else {
+ diag.span_note(
+ sp,
+ &format!("format specifiers use curly braces, and {}", trn),
+ );
}
-
- if let Some(inner_sp) = pos {
- let sp = fmt_sp.from_inner(inner_sp);
-
- if success {
- suggestions.push((sp, trn));
- } else {
- diag.span_note(
- sp,
- &format!("format specifiers use curly braces, and {}", trn),
- );
- }
+ } else {
+ if success {
+ diag.help(&format!("`{}` should be written as `{}`", sub, trn));
} else {
- if success {
- 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));
}
}
+ }
- if show_doc_note {
- diag.note(concat!(
- stringify!($kind),
- " formatting not supported; see the documentation for `std::fmt`",
- ));
- }
- if suggestions.len() > 0 {
- diag.multipart_suggestion(
- "format specifiers use curly braces",
- suggestions,
- Applicability::MachineApplicable,
- );
- }
- }};
- }
-
- check_foreign!(printf);
- if !found_foreign {
- check_foreign!(shell);
- }
- }
- if !found_foreign && errs_len == 1 {
- diag.span_label(cx.fmtsp, "formatting specifier missing");
+ if show_doc_note {
+ diag.note(concat!(
+ stringify!($kind),
+ " formatting not supported; see the documentation for `std::fmt`",
+ ));
+ }
+ if suggestions.len() > 0 {
+ diag.multipart_suggestion(
+ "format specifiers use curly braces",
+ suggestions,
+ Applicability::MachineApplicable,
+ );
+ }
+ }};
}
- diag.emit();
- } else if cx.invalid_refs.is_empty() && cx.ecx.sess.err_count() == 0 {
- // Only check for unused named argument names if there are no other errors to avoid causing
- // too much noise in output errors, such as when a named argument is entirely unused.
- create_lints_for_named_arguments_used_positionally(&mut cx);
+ check_foreign!(printf);
+ if !found_foreign {
+ check_foreign!(shell);
+ }
+ }
+ if !found_foreign && unused.len() == 1 {
+ diag.span_label(fmt_span, "formatting specifier missing");
}
- cx.into_expr()
+ diag.emit();
}
-fn may_contain_yield_point(e: &ast::Expr) -> bool {
- struct MayContainYieldPoint(bool);
+/// Handle invalid references to positional arguments. Output different
+/// errors for the case where all arguments are positional and for when
+/// there are named arguments or numbered positional arguments in the
+/// format string.
+fn report_invalid_references(
+ ecx: &mut ExtCtxt<'_>,
+ invalid_refs: &[(usize, Option<Span>, PositionUsedAs, FormatArgPositionKind)],
+ template: &[FormatArgsPiece],
+ fmt_span: Span,
+ args: &FormatArguments,
+ parser: parse::Parser<'_>,
+) {
+ let num_args_desc = match args.explicit_args().len() {
+ 0 => "no arguments were given".to_string(),
+ 1 => "there is 1 argument".to_string(),
+ n => format!("there are {} arguments", n),
+ };
+
+ let mut e;
- impl Visitor<'_> for MayContainYieldPoint {
- fn visit_expr(&mut self, e: &ast::Expr) {
- if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind {
- self.0 = true;
- } else {
- visit::walk_expr(self, e);
+ if template.iter().all(|piece| match piece {
+ FormatArgsPiece::Placeholder(FormatPlaceholder {
+ argument: FormatArgPosition { kind: FormatArgPositionKind::Number, .. },
+ ..
+ }) => false,
+ FormatArgsPiece::Placeholder(FormatPlaceholder {
+ format_options:
+ FormatOptions {
+ precision:
+ Some(FormatCount::Argument(FormatArgPosition {
+ kind: FormatArgPositionKind::Number,
+ ..
+ })),
+ ..
+ }
+ | FormatOptions {
+ width:
+ Some(FormatCount::Argument(FormatArgPosition {
+ kind: FormatArgPositionKind::Number,
+ ..
+ })),
+ ..
+ },
+ ..
+ }) => false,
+ _ => true,
+ }) {
+ // There are no numeric positions.
+ // Collect all the implicit positions:
+ let mut spans = Vec::new();
+ let mut num_placeholders = 0;
+ for piece in template {
+ let mut placeholder = None;
+ // `{arg:.*}`
+ if let FormatArgsPiece::Placeholder(FormatPlaceholder {
+ format_options:
+ FormatOptions {
+ precision:
+ Some(FormatCount::Argument(FormatArgPosition {
+ span,
+ kind: FormatArgPositionKind::Implicit,
+ ..
+ })),
+ ..
+ },
+ ..
+ }) = piece
+ {
+ placeholder = *span;
+ num_placeholders += 1;
}
+ // `{}`
+ if let FormatArgsPiece::Placeholder(FormatPlaceholder {
+ argument: FormatArgPosition { kind: FormatArgPositionKind::Implicit, .. },
+ span,
+ ..
+ }) = piece
+ {
+ placeholder = *span;
+ num_placeholders += 1;
+ }
+ // For `{:.*}`, we only push one span.
+ spans.extend(placeholder);
}
-
- fn visit_mac_call(&mut self, _: &ast::MacCall) {
- self.0 = true;
+ let span = if spans.is_empty() {
+ MultiSpan::from_span(fmt_span)
+ } else {
+ MultiSpan::from_spans(spans)
+ };
+ e = ecx.struct_span_err(
+ span,
+ &format!(
+ "{} positional argument{} in format string, but {}",
+ num_placeholders,
+ pluralize!(num_placeholders),
+ num_args_desc,
+ ),
+ );
+ for arg in args.explicit_args() {
+ e.span_label(arg.expr.span, "");
+ }
+ // Point out `{:.*}` placeholders: those take an extra argument.
+ let mut has_precision_star = false;
+ for piece in template {
+ if let FormatArgsPiece::Placeholder(FormatPlaceholder {
+ format_options:
+ FormatOptions {
+ precision:
+ Some(FormatCount::Argument(FormatArgPosition {
+ index,
+ span: Some(span),
+ kind: FormatArgPositionKind::Implicit,
+ ..
+ })),
+ ..
+ },
+ ..
+ }) = piece
+ {
+ let (Ok(index) | Err(index)) = index;
+ has_precision_star = true;
+ e.span_label(
+ *span,
+ &format!(
+ "this precision flag adds an extra required argument at position {}, which is why there {} expected",
+ index,
+ if num_placeholders == 1 {
+ "is 1 argument".to_string()
+ } else {
+ format!("are {} arguments", num_placeholders)
+ },
+ ),
+ );
+ }
+ }
+ if has_precision_star {
+ e.note("positional arguments are zero-based");
}
+ } else {
+ let mut indexes: Vec<_> = invalid_refs.iter().map(|&(index, _, _, _)| index).collect();
+ // Avoid `invalid reference to positional arguments 7 and 7 (there is 1 argument)`
+ // for `println!("{7:7$}", 1);`
+ indexes.sort();
+ indexes.dedup();
+ let span: MultiSpan = if !parser.is_literal || parser.arg_places.is_empty() {
+ MultiSpan::from_span(fmt_span)
+ } else {
+ MultiSpan::from_spans(invalid_refs.iter().filter_map(|&(_, span, _, _)| span).collect())
+ };
+ let arg_list = if let &[index] = &indexes[..] {
+ format!("argument {index}")
+ } else {
+ let tail = indexes.pop().unwrap();
+ format!(
+ "arguments {head} and {tail}",
+ head = indexes.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(", ")
+ )
+ };
+ e = ecx.struct_span_err(
+ span,
+ &format!("invalid reference to positional {} ({})", arg_list, num_args_desc),
+ );
+ e.note("positional arguments are zero-based");
+ }
- fn visit_attribute(&mut self, _: &ast::Attribute) {
- // Conservatively assume this may be a proc macro attribute in
- // expression position.
- self.0 = true;
+ if template.iter().any(|piece| match piece {
+ FormatArgsPiece::Placeholder(FormatPlaceholder { format_options: f, .. }) => {
+ *f != FormatOptions::default()
}
+ _ => false,
+ }) {
+ e.note("for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html");
+ }
+
+ e.emit();
+}
- fn visit_item(&mut self, _: &ast::Item) {
- // Do not recurse into nested items.
+fn expand_format_args_impl<'cx>(
+ ecx: &'cx mut ExtCtxt<'_>,
+ mut sp: Span,
+ tts: TokenStream,
+ nl: bool,
+) -> Box<dyn base::MacResult + 'cx> {
+ sp = ecx.with_def_site_ctxt(sp);
+ match parse_args(ecx, sp, tts) {
+ Ok((efmt, args)) => {
+ if let Ok(format_args) = make_format_args(ecx, efmt, args, nl) {
+ MacEager::expr(expand_parsed_format_args(ecx, format_args))
+ } else {
+ MacEager::expr(DummyResult::raw_expr(sp, true))
+ }
+ }
+ Err(mut err) => {
+ err.emit();
+ DummyResult::any(sp)
}
}
+}
+
+pub fn expand_format_args<'cx>(
+ ecx: &'cx mut ExtCtxt<'_>,
+ sp: Span,
+ tts: TokenStream,
+) -> Box<dyn base::MacResult + 'cx> {
+ expand_format_args_impl(ecx, sp, tts, false)
+}
- let mut visitor = MayContainYieldPoint(false);
- visitor.visit_expr(e);
- visitor.0
+pub fn expand_format_args_nl<'cx>(
+ ecx: &'cx mut ExtCtxt<'_>,
+ sp: Span,
+ tts: TokenStream,
+) -> Box<dyn base::MacResult + 'cx> {
+ expand_format_args_impl(ecx, sp, tts, true)
}
diff --git a/compiler/rustc_builtin_macros/src/format/ast.rs b/compiler/rustc_builtin_macros/src/format/ast.rs
new file mode 100644
index 000000000..01dbffa21
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/format/ast.rs
@@ -0,0 +1,240 @@
+use rustc_ast::ptr::P;
+use rustc_ast::Expr;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::Span;
+
+// Definitions:
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+// └──────────────────────────────────────────────┘
+// FormatArgs
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+// └─────────┘
+// argument
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+// └───────────────────┘
+// template
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+// └────┘└─────────┘└┘
+// pieces
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+// └────┘ └┘
+// literal pieces
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+// └─────────┘
+// placeholder
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+// └─┘ └─┘
+// positions (could be names, numbers, empty, or `*`)
+
+/// (Parsed) format args.
+///
+/// Basically the "AST" for a complete `format_args!()`.
+///
+/// E.g., `format_args!("hello {name}");`.
+#[derive(Clone, Debug)]
+pub struct FormatArgs {
+ pub span: Span,
+ pub template: Vec<FormatArgsPiece>,
+ pub arguments: FormatArguments,
+}
+
+/// A piece of a format template string.
+///
+/// E.g. "hello" or "{name}".
+#[derive(Clone, Debug)]
+pub enum FormatArgsPiece {
+ Literal(Symbol),
+ Placeholder(FormatPlaceholder),
+}
+
+/// The arguments to format_args!().
+///
+/// E.g. `1, 2, name="ferris", n=3`,
+/// but also implicit captured arguments like `x` in `format_args!("{x}")`.
+#[derive(Clone, Debug)]
+pub struct FormatArguments {
+ arguments: Vec<FormatArgument>,
+ num_unnamed_args: usize,
+ num_explicit_args: usize,
+ names: FxHashMap<Symbol, usize>,
+}
+
+impl FormatArguments {
+ pub fn new() -> Self {
+ Self {
+ arguments: Vec::new(),
+ names: FxHashMap::default(),
+ num_unnamed_args: 0,
+ num_explicit_args: 0,
+ }
+ }
+
+ pub fn add(&mut self, arg: FormatArgument) -> usize {
+ let index = self.arguments.len();
+ if let Some(name) = arg.kind.ident() {
+ self.names.insert(name.name, index);
+ } else if self.names.is_empty() {
+ // Only count the unnamed args before the first named arg.
+ // (Any later ones are errors.)
+ self.num_unnamed_args += 1;
+ }
+ if !matches!(arg.kind, FormatArgumentKind::Captured(..)) {
+ // This is an explicit argument.
+ // Make sure that all arguments so far are explcit.
+ assert_eq!(
+ self.num_explicit_args,
+ self.arguments.len(),
+ "captured arguments must be added last"
+ );
+ self.num_explicit_args += 1;
+ }
+ self.arguments.push(arg);
+ index
+ }
+
+ pub fn by_name(&self, name: Symbol) -> Option<(usize, &FormatArgument)> {
+ let i = *self.names.get(&name)?;
+ Some((i, &self.arguments[i]))
+ }
+
+ pub fn by_index(&self, i: usize) -> Option<&FormatArgument> {
+ (i < self.num_explicit_args).then(|| &self.arguments[i])
+ }
+
+ pub fn unnamed_args(&self) -> &[FormatArgument] {
+ &self.arguments[..self.num_unnamed_args]
+ }
+
+ pub fn named_args(&self) -> &[FormatArgument] {
+ &self.arguments[self.num_unnamed_args..self.num_explicit_args]
+ }
+
+ pub fn explicit_args(&self) -> &[FormatArgument] {
+ &self.arguments[..self.num_explicit_args]
+ }
+
+ pub fn into_vec(self) -> Vec<FormatArgument> {
+ self.arguments
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct FormatArgument {
+ pub kind: FormatArgumentKind,
+ pub expr: P<Expr>,
+}
+
+#[derive(Clone, Debug)]
+pub enum FormatArgumentKind {
+ /// `format_args(…, arg)`
+ Normal,
+ /// `format_args(…, arg = 1)`
+ Named(Ident),
+ /// `format_args("… {arg} …")`
+ Captured(Ident),
+}
+
+impl FormatArgumentKind {
+ pub fn ident(&self) -> Option<Ident> {
+ match self {
+ &Self::Normal => None,
+ &Self::Named(id) => Some(id),
+ &Self::Captured(id) => Some(id),
+ }
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct FormatPlaceholder {
+ /// Index into [`FormatArgs::arguments`].
+ pub argument: FormatArgPosition,
+ /// The span inside the format string for the full `{…}` placeholder.
+ pub span: Option<Span>,
+ /// `{}`, `{:?}`, or `{:x}`, etc.
+ pub format_trait: FormatTrait,
+ /// `{}` or `{:.5}` or `{:-^20}`, etc.
+ pub format_options: FormatOptions,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct FormatArgPosition {
+ /// Which argument this position refers to (Ok),
+ /// or would've referred to if it existed (Err).
+ pub index: Result<usize, usize>,
+ /// What kind of position this is. See [`FormatArgPositionKind`].
+ pub kind: FormatArgPositionKind,
+ /// The span of the name or number.
+ pub span: Option<Span>,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum FormatArgPositionKind {
+ /// `{}` or `{:.*}`
+ Implicit,
+ /// `{1}` or `{:1$}` or `{:.1$}`
+ Number,
+ /// `{a}` or `{:a$}` or `{:.a$}`
+ Named,
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub enum FormatTrait {
+ /// `{}`
+ Display,
+ /// `{:?}`
+ Debug,
+ /// `{:e}`
+ LowerExp,
+ /// `{:E}`
+ UpperExp,
+ /// `{:o}`
+ Octal,
+ /// `{:p}`
+ Pointer,
+ /// `{:b}`
+ Binary,
+ /// `{:x}`
+ LowerHex,
+ /// `{:X}`
+ UpperHex,
+}
+
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
+pub struct FormatOptions {
+ /// The width. E.g. `{:5}` or `{:width$}`.
+ pub width: Option<FormatCount>,
+ /// The precision. E.g. `{:.5}` or `{:.precision$}`.
+ pub precision: Option<FormatCount>,
+ /// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`.
+ pub alignment: Option<FormatAlignment>,
+ /// The fill character. E.g. the `.` in `{:.>10}`.
+ pub fill: Option<char>,
+ /// The `+`, `-`, `0`, `#`, `x?` and `X?` flags.
+ pub flags: u32,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum FormatAlignment {
+ /// `{:<}`
+ Left,
+ /// `{:>}`
+ Right,
+ /// `{:^}`
+ Center,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum FormatCount {
+ /// `{:5}` or `{:.5}`
+ Literal(usize),
+ /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc.
+ Argument(FormatArgPosition),
+}
diff --git a/compiler/rustc_builtin_macros/src/format/expand.rs b/compiler/rustc_builtin_macros/src/format/expand.rs
new file mode 100644
index 000000000..9dde5efcb
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/format/expand.rs
@@ -0,0 +1,353 @@
+use super::*;
+use rustc_ast as ast;
+use rustc_ast::visit::{self, Visitor};
+use rustc_ast::{BlockCheckMode, UnsafeSource};
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_span::{sym, symbol::kw};
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+enum ArgumentType {
+ Format(FormatTrait),
+ Usize,
+}
+
+fn make_argument(ecx: &ExtCtxt<'_>, sp: Span, arg: P<ast::Expr>, ty: ArgumentType) -> P<ast::Expr> {
+ // Generate:
+ // ::core::fmt::ArgumentV1::new_…(arg)
+ use ArgumentType::*;
+ use FormatTrait::*;
+ ecx.expr_call_global(
+ sp,
+ ecx.std_path(&[
+ sym::fmt,
+ sym::ArgumentV1,
+ match ty {
+ Format(Display) => sym::new_display,
+ Format(Debug) => sym::new_debug,
+ Format(LowerExp) => sym::new_lower_exp,
+ Format(UpperExp) => sym::new_upper_exp,
+ Format(Octal) => sym::new_octal,
+ Format(Pointer) => sym::new_pointer,
+ Format(Binary) => sym::new_binary,
+ Format(LowerHex) => sym::new_lower_hex,
+ Format(UpperHex) => sym::new_upper_hex,
+ Usize => sym::from_usize,
+ },
+ ]),
+ vec![arg],
+ )
+}
+
+fn make_count(
+ ecx: &ExtCtxt<'_>,
+ sp: Span,
+ count: &Option<FormatCount>,
+ argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+) -> P<ast::Expr> {
+ // Generate:
+ // ::core::fmt::rt::v1::Count::…(…)
+ match count {
+ Some(FormatCount::Literal(n)) => ecx.expr_call_global(
+ sp,
+ ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Is]),
+ vec![ecx.expr_usize(sp, *n)],
+ ),
+ Some(FormatCount::Argument(arg)) => {
+ if let Ok(arg_index) = arg.index {
+ let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
+ ecx.expr_call_global(
+ sp,
+ ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Param]),
+ vec![ecx.expr_usize(sp, i)],
+ )
+ } else {
+ DummyResult::raw_expr(sp, true)
+ }
+ }
+ None => ecx.expr_path(ecx.path_global(
+ sp,
+ ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Implied]),
+ )),
+ }
+}
+
+fn make_format_spec(
+ ecx: &ExtCtxt<'_>,
+ sp: Span,
+ placeholder: &FormatPlaceholder,
+ argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+) -> P<ast::Expr> {
+ // Generate:
+ // ::core::fmt::rt::v1::Argument {
+ // position: 0usize,
+ // format: ::core::fmt::rt::v1::FormatSpec {
+ // fill: ' ',
+ // align: ::core::fmt::rt::v1::Alignment::Unknown,
+ // flags: 0u32,
+ // precision: ::core::fmt::rt::v1::Count::Implied,
+ // width: ::core::fmt::rt::v1::Count::Implied,
+ // },
+ // }
+ let position = match placeholder.argument.index {
+ Ok(arg_index) => {
+ let (i, _) =
+ argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
+ ecx.expr_usize(sp, i)
+ }
+ Err(_) => DummyResult::raw_expr(sp, true),
+ };
+ let fill = ecx.expr_char(sp, placeholder.format_options.fill.unwrap_or(' '));
+ let align = ecx.expr_path(ecx.path_global(
+ sp,
+ ecx.std_path(&[
+ sym::fmt,
+ sym::rt,
+ sym::v1,
+ sym::Alignment,
+ match placeholder.format_options.alignment {
+ Some(FormatAlignment::Left) => sym::Left,
+ Some(FormatAlignment::Right) => sym::Right,
+ Some(FormatAlignment::Center) => sym::Center,
+ None => sym::Unknown,
+ },
+ ]),
+ ));
+ let flags = ecx.expr_u32(sp, placeholder.format_options.flags);
+ let prec = make_count(ecx, sp, &placeholder.format_options.precision, argmap);
+ let width = make_count(ecx, sp, &placeholder.format_options.width, argmap);
+ ecx.expr_struct(
+ sp,
+ ecx.path_global(sp, ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Argument])),
+ vec![
+ ecx.field_imm(sp, Ident::new(sym::position, sp), position),
+ ecx.field_imm(
+ sp,
+ Ident::new(sym::format, sp),
+ ecx.expr_struct(
+ sp,
+ ecx.path_global(
+ sp,
+ ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::FormatSpec]),
+ ),
+ vec![
+ ecx.field_imm(sp, Ident::new(sym::fill, sp), fill),
+ ecx.field_imm(sp, Ident::new(sym::align, sp), align),
+ ecx.field_imm(sp, Ident::new(sym::flags, sp), flags),
+ ecx.field_imm(sp, Ident::new(sym::precision, sp), prec),
+ ecx.field_imm(sp, Ident::new(sym::width, sp), width),
+ ],
+ ),
+ ),
+ ],
+ )
+}
+
+pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<ast::Expr> {
+ let macsp = ecx.with_def_site_ctxt(ecx.call_site());
+
+ let lit_pieces = ecx.expr_array_ref(
+ fmt.span,
+ fmt.template
+ .iter()
+ .enumerate()
+ .filter_map(|(i, piece)| match piece {
+ &FormatArgsPiece::Literal(s) => Some(ecx.expr_str(fmt.span, s)),
+ &FormatArgsPiece::Placeholder(_) => {
+ // Inject empty string before placeholders when not already preceded by a literal piece.
+ if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) {
+ Some(ecx.expr_str(fmt.span, kw::Empty))
+ } else {
+ None
+ }
+ }
+ })
+ .collect(),
+ );
+
+ // Whether we'll use the `Arguments::new_v1_formatted` form (true),
+ // or the `Arguments::new_v1` form (false).
+ let mut use_format_options = false;
+
+ // Create a list of all _unique_ (argument, format trait) combinations.
+ // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
+ let mut argmap = FxIndexSet::default();
+ for piece in &fmt.template {
+ let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
+ if placeholder.format_options != Default::default() {
+ // Can't use basic form if there's any formatting options.
+ use_format_options = true;
+ }
+ if let Ok(index) = placeholder.argument.index {
+ if !argmap.insert((index, ArgumentType::Format(placeholder.format_trait))) {
+ // Duplicate (argument, format trait) combination,
+ // which we'll only put once in the args array.
+ use_format_options = true;
+ }
+ }
+ }
+
+ let format_options = use_format_options.then(|| {
+ // Generate:
+ // &[format_spec_0, format_spec_1, format_spec_2]
+ ecx.expr_array_ref(
+ macsp,
+ fmt.template
+ .iter()
+ .filter_map(|piece| {
+ let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
+ Some(make_format_spec(ecx, macsp, placeholder, &mut argmap))
+ })
+ .collect(),
+ )
+ });
+
+ let arguments = fmt.arguments.into_vec();
+
+ // 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.
+ let use_simple_array = argmap.len() == arguments.len()
+ && 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 {
+ // Generate:
+ // &[
+ // ::core::fmt::ArgumentV1::new_display(&arg0),
+ // ::core::fmt::ArgumentV1::new_lower_hex(&arg1),
+ // ::core::fmt::ArgumentV1::new_debug(&arg2),
+ // ]
+ ecx.expr_array_ref(
+ macsp,
+ arguments
+ .into_iter()
+ .zip(argmap)
+ .map(|(arg, (_, ty))| {
+ let sp = arg.expr.span.with_ctxt(macsp.ctxt());
+ make_argument(ecx, sp, ecx.expr_addr_of(sp, arg.expr), ty)
+ })
+ .collect(),
+ )
+ } else {
+ // Generate:
+ // match (&arg0, &arg1, &arg2) {
+ // args => &[
+ // ::core::fmt::ArgumentV1::new_display(args.0),
+ // ::core::fmt::ArgumentV1::new_lower_hex(args.1),
+ // ::core::fmt::ArgumentV1::new_debug(args.0),
+ // ]
+ // }
+ let args_ident = Ident::new(sym::args, macsp);
+ let args = argmap
+ .iter()
+ .map(|&(arg_index, ty)| {
+ if let Some(arg) = arguments.get(arg_index) {
+ let sp = arg.expr.span.with_ctxt(macsp.ctxt());
+ make_argument(
+ ecx,
+ sp,
+ ecx.expr_field(
+ sp,
+ ecx.expr_ident(macsp, args_ident),
+ Ident::new(sym::integer(arg_index), macsp),
+ ),
+ ty,
+ )
+ } else {
+ DummyResult::raw_expr(macsp, true)
+ }
+ })
+ .collect();
+ ecx.expr_addr_of(
+ macsp,
+ ecx.expr_match(
+ macsp,
+ ecx.expr_tuple(
+ macsp,
+ arguments
+ .into_iter()
+ .map(|arg| {
+ ecx.expr_addr_of(arg.expr.span.with_ctxt(macsp.ctxt()), arg.expr)
+ })
+ .collect(),
+ ),
+ vec![ecx.arm(macsp, ecx.pat_ident(macsp, args_ident), ecx.expr_array(macsp, args))],
+ ),
+ )
+ };
+
+ if let Some(format_options) = format_options {
+ // Generate:
+ // ::core::fmt::Arguments::new_v1_formatted(
+ // lit_pieces,
+ // args,
+ // format_options,
+ // unsafe { ::core::fmt::UnsafeArg::new() }
+ // )
+ ecx.expr_call_global(
+ macsp,
+ ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1_formatted]),
+ vec![
+ lit_pieces,
+ args,
+ format_options,
+ ecx.expr_block(P(ast::Block {
+ stmts: vec![ecx.stmt_expr(ecx.expr_call_global(
+ macsp,
+ ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]),
+ Vec::new(),
+ ))],
+ id: ast::DUMMY_NODE_ID,
+ rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
+ span: macsp,
+ tokens: None,
+ could_be_bare_literal: false,
+ })),
+ ],
+ )
+ } else {
+ // Generate:
+ // ::core::fmt::Arguments::new_v1(
+ // lit_pieces,
+ // args,
+ // )
+ ecx.expr_call_global(
+ macsp,
+ ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1]),
+ vec![lit_pieces, args],
+ )
+ }
+}
+
+fn may_contain_yield_point(e: &ast::Expr) -> bool {
+ struct MayContainYieldPoint(bool);
+
+ impl Visitor<'_> for MayContainYieldPoint {
+ fn visit_expr(&mut self, e: &ast::Expr) {
+ if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind {
+ self.0 = true;
+ } else {
+ visit::walk_expr(self, e);
+ }
+ }
+
+ fn visit_mac_call(&mut self, _: &ast::MacCall) {
+ self.0 = true;
+ }
+
+ fn visit_attribute(&mut self, _: &ast::Attribute) {
+ // Conservatively assume this may be a proc macro attribute in
+ // expression position.
+ self.0 = true;
+ }
+
+ fn visit_item(&mut self, _: &ast::Item) {
+ // Do not recurse into nested items.
+ }
+ }
+
+ let mut visitor = MayContainYieldPoint(false);
+ visitor.visit_expr(e);
+ visitor.0
+}
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 8aeb3b82a..c7ea7de8f 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -7,9 +7,9 @@
#![feature(box_patterns)]
#![feature(decl_macro)]
#![feature(if_let_guard)]
+#![feature(is_some_and)]
#![feature(is_sorted)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(proc_macro_internals)]
#![feature(proc_macro_quote)]
#![recursion_limit = "256"]
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 7efb6cc61..fee5d04cd 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -36,13 +36,22 @@ pub fn expand_test_case(
let sp = ecx.with_def_site_ctxt(attr_sp);
let mut item = anno_item.expect_item();
item = item.map(|mut item| {
+ let test_path_symbol = Symbol::intern(&item_path(
+ // skip the name of the root module
+ &ecx.current_expansion.module.mod_path[1..],
+ &item.ident,
+ ));
item.vis = ast::Visibility {
span: item.vis.span,
kind: ast::VisibilityKind::Public,
tokens: None,
};
item.ident.span = item.ident.span.with_ctxt(sp.ctxt());
- item.attrs.push(ecx.attribute(ecx.meta_word(sp, sym::rustc_test_marker)));
+ item.attrs.push(ecx.attribute(attr::mk_name_value_item_str(
+ Ident::new(sym::rustc_test_marker, sp),
+ test_path_symbol,
+ sp,
+ )));
item
});
@@ -115,7 +124,7 @@ pub fn expand_test_or_bench(
// reworked in the future to not need it, it'd be nice.
_ => diag.struct_span_err(attr_sp, msg).forget_guarantee(),
};
- err.span_label(attr_sp, "the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions")
+ err.span_label(attr_sp, "the `#[test]` macro causes a function to be run on a test and has no effect on non-functions")
.span_label(item.span, format!("expected a non-associated function, found {} {}", item.kind.article(), item.kind.descr()))
.span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", "#[cfg(test)]", Applicability::MaybeIncorrect)
.emit();
@@ -215,6 +224,12 @@ pub fn expand_test_or_bench(
)
};
+ let test_path_symbol = Symbol::intern(&item_path(
+ // skip the name of the root module
+ &cx.current_expansion.module.mod_path[1..],
+ &item.ident,
+ ));
+
let mut test_const = cx.item(
sp,
Ident::new(item.ident.name, sp),
@@ -224,9 +239,14 @@ pub fn expand_test_or_bench(
Ident::new(sym::cfg, attr_sp),
vec![attr::mk_nested_word_item(Ident::new(sym::test, attr_sp))],
)),
- // #[rustc_test_marker]
- cx.attribute(cx.meta_word(attr_sp, sym::rustc_test_marker)),
- ],
+ // #[rustc_test_marker = "test_case_sort_key"]
+ cx.attribute(attr::mk_name_value_item_str(
+ Ident::new(sym::rustc_test_marker, attr_sp),
+ test_path_symbol,
+ attr_sp,
+ )),
+ ]
+ .into(),
// const $ident: test::TestDescAndFn =
ast::ItemKind::Const(
ast::Defaultness::Final,
@@ -250,14 +270,7 @@ pub fn expand_test_or_bench(
cx.expr_call(
sp,
cx.expr_path(test_path("StaticTestName")),
- vec![cx.expr_str(
- sp,
- Symbol::intern(&item_path(
- // skip the name of the root module
- &cx.current_expansion.module.mod_path[1..],
- &item.ident,
- )),
- )],
+ vec![cx.expr_str(sp, test_path_symbol)],
),
),
// ignore: true | false
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 561ca00c7..b8b8351a3 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -18,9 +18,11 @@ use thin_vec::thin_vec;
use std::{iter, mem};
+#[derive(Clone)]
struct Test {
span: Span,
ident: Ident,
+ name: Symbol,
}
struct TestCtxt<'a> {
@@ -120,10 +122,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
let mut item = i.into_inner();
- if is_test_case(&self.cx.ext_cx.sess, &item) {
+ if let Some(name) = get_test_name(&self.cx.ext_cx.sess, &item) {
debug!("this is a test item");
- let test = Test { span: item.span, ident: item.ident };
+ let test = Test { span: item.span, ident: item.ident, name };
self.tests.push(test);
}
@@ -357,9 +359,12 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> {
debug!("building test vector from {} tests", cx.test_cases.len());
let ecx = &cx.ext_cx;
+ let mut tests = cx.test_cases.clone();
+ tests.sort_by(|a, b| a.name.as_str().cmp(&b.name.as_str()));
+
ecx.expr_array_ref(
sp,
- cx.test_cases
+ tests
.iter()
.map(|test| {
ecx.expr_addr_of(test.span, ecx.expr_path(ecx.path(test.span, vec![test.ident])))
@@ -368,8 +373,8 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> {
)
}
-fn is_test_case(sess: &Session, i: &ast::Item) -> bool {
- sess.contains_name(&i.attrs, sym::rustc_test_marker)
+fn get_test_name(sess: &Session, i: &ast::Item) -> Option<Symbol> {
+ sess.first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker)
}
fn get_test_runner(
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index e8897e9ae..5061010c8 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -29,7 +29,11 @@ jobs:
matrix:
include:
- os: ubuntu-latest
+ env:
+ TARGET_TRIPLE: x86_64-unknown-linux-gnu
- os: macos-latest
+ env:
+ TARGET_TRIPLE: x86_64-apple-darwin
# cross-compile from Linux to Windows using mingw
- os: ubuntu-latest
env:
@@ -112,7 +116,7 @@ jobs:
if: matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
uses: actions/upload-artifact@v2
with:
- name: cg_clif-${{ runner.os }}
+ name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
path: cg_clif.tar.xz
- name: Upload prebuilt cg_clif (cross compile)
@@ -122,56 +126,89 @@ jobs:
name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
path: cg_clif.tar.xz
- build_windows:
- runs-on: windows-latest
+ windows:
+ runs-on: ${{ matrix.os }}
timeout-minutes: 60
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ # Native Windows build with MSVC
+ - os: windows-latest
+ env:
+ TARGET_TRIPLE: x86_64-pc-windows-msvc
+ # cross-compile from Windows to Windows MinGW
+ - os: windows-latest
+ env:
+ TARGET_TRIPLE: x86_64-pc-windows-gnu
+
steps:
- uses: actions/checkout@v3
- #- name: Cache cargo installed crates
- # uses: actions/cache@v2
- # with:
- # path: ~/.cargo/bin
- # key: ${{ runner.os }}-cargo-installed-crates
-
- #- name: Cache cargo registry and index
- # uses: actions/cache@v2
- # with:
- # path: |
- # ~/.cargo/registry
- # ~/.cargo/git
- # key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
-
- #- name: Cache cargo target dir
- # uses: actions/cache@v2
- # with:
- # path: target
- # key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
+ - name: Cache cargo installed crates
+ uses: actions/cache@v2
+ with:
+ path: ~/.cargo/bin
+ key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-installed-crates
+
+ - name: Cache cargo registry and index
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.cargo/registry
+ ~/.cargo/git
+ key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
+
+ - name: Cache cargo target dir
+ uses: actions/cache@v2
+ with:
+ path: target
+ key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
+
+ - name: Set MinGW as the default toolchain
+ if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
+ run: rustup set default-host x86_64-pc-windows-gnu
- name: Prepare dependencies
run: |
git config --global user.email "user@example.com"
git config --global user.name "User"
git config --global core.autocrlf false
- rustup set default-host x86_64-pc-windows-gnu
rustc y.rs -o y.exe -g
./y.exe prepare
+ - name: Build without unstable features
+ env:
+ TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
+ # This is the config rust-lang/rust uses for builds
+ run: ./y.rs build --no-unstable-features
+
- name: Build
- #name: Test
+ run: ./y.rs build --sysroot none
+
+ - name: Test
run: |
# Enable backtraces for easier debugging
- #$Env:RUST_BACKTRACE=1
+ $Env:RUST_BACKTRACE=1
# Reduce amount of benchmark runs as they are slow
- #$Env:COMPILE_RUNS=2
- #$Env:RUN_RUNS=2
+ $Env:COMPILE_RUNS=2
+ $Env:RUN_RUNS=2
# Enable extra checks
- #$Env:CG_CLIF_ENABLE_VERIFIER=1
-
- ./y.exe build
+ $Env:CG_CLIF_ENABLE_VERIFIER=1
+
+ # WIP Disable some tests
+
+ # This fails due to some weird argument handling by hyperfine, not an actual regression
+ # more of a build system issue
+ (Get-Content config.txt) -replace '(bench.simple-raytracer)', '# $1' | Out-File config.txt
+
+ # This fails with a different output than expected
+ (Get-Content config.txt) -replace '(test.regex-shootout-regex-dna)', '# $1' | Out-File config.txt
+
+ ./y.exe test
- name: Package prebuilt cg_clif
# don't use compression as xzip isn't supported by tar on windows and bzip2 hangs
@@ -180,5 +217,5 @@ jobs:
- name: Upload prebuilt cg_clif
uses: actions/upload-artifact@v2
with:
- name: cg_clif-${{ runner.os }}
+ name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
path: cg_clif.tar
diff --git a/compiler/rustc_codegen_cranelift/.vscode/settings.json b/compiler/rustc_codegen_cranelift/.vscode/settings.json
index d88309e41..13301bf20 100644
--- a/compiler/rustc_codegen_cranelift/.vscode/settings.json
+++ b/compiler/rustc_codegen_cranelift/.vscode/settings.json
@@ -7,7 +7,7 @@
"rust-analyzer.cargo.features": ["unstable-features"],
"rust-analyzer.linkedProjects": [
"./Cargo.toml",
- //"./build_sysroot/sysroot_src/src/libstd/Cargo.toml",
+ //"./build_sysroot/sysroot_src/library/std/Cargo.toml",
{
"roots": [
"./example/mini_core.rs",
@@ -36,10 +36,10 @@
]
},
{
- "roots": ["./scripts/filter_profile.rs"],
+ "roots": ["./example/std_example.rs"],
"crates": [
{
- "root_module": "./scripts/filter_profile.rs",
+ "root_module": "./example/std_example.rs",
"edition": "2018",
"deps": [{ "crate": 1, "name": "std" }],
"cfg": [],
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index edae7e471..3fa9d56cd 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -25,6 +25,12 @@ version = "0.8.0"
source = "git+https://github.com/bjorn3/rust-ar.git?branch=do_not_remove_cg_clif_ranlib#de9ab0e56bf3a208381d342aa5b60f9ff2891648"
[[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"
@@ -37,6 +43,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
+name = "bumpalo"
+version = "3.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
+
+[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -50,19 +62,21 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cranelift-bforest"
-version = "0.87.0"
+version = "0.88.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93945adbccc8d731503d3038814a51e8317497c9e205411820348132fa01a358"
+checksum = "44409ccf2d0f663920cab563d2b79fcd6b2e9a2bcc6e929fef76c8f82ad6c17a"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
-version = "0.87.0"
+version = "0.88.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b482acc9d0d0d1ad3288a90a8150ee648be3dce8dc8c8669ff026f72debdc31"
+checksum = "98de2018ad96eb97f621f7d6b900a0cc661aec8d02ea4a50e56ecb48e5a2fcaf"
dependencies = [
+ "arrayvec",
+ "bumpalo",
"cranelift-bforest",
"cranelift-codegen-meta",
"cranelift-codegen-shared",
@@ -77,30 +91,30 @@ dependencies = [
[[package]]
name = "cranelift-codegen-meta"
-version = "0.87.0"
+version = "0.88.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9ec188d71e663192ef9048f204e410a7283b609942efc9fcc77da6d496edbb8"
+checksum = "5287ce36e6c4758fbaf298bd1a8697ad97a4f2375a3d1b61142ea538db4877e5"
dependencies = [
"cranelift-codegen-shared",
]
[[package]]
name = "cranelift-codegen-shared"
-version = "0.87.0"
+version = "0.88.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ad794b1b1c2c7bd9f7b76cfe0f084eaf7753e55d56191c3f7d89e8fa4978b99"
+checksum = "2855c24219e2f08827f3f4ffb2da92e134ae8d8ecc185b11ec8f9878cf5f588e"
[[package]]
name = "cranelift-entity"
-version = "0.87.0"
+version = "0.88.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "342da0d5056f4119d3c311c4aab2460ceb6ee6e127bb395b76dd2279a09ea7a5"
+checksum = "0b65673279d75d34bf11af9660ae2dbd1c22e6d28f163f5c72f4e1dc56d56103"
[[package]]
name = "cranelift-frontend"
-version = "0.87.0"
+version = "0.88.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfff792f775b07d4d9cfe9f1c767ce755c6cbadda1bbd6db18a1c75ff9f7376a"
+checksum = "3ed2b3d7a4751163f6c4a349205ab1b7d9c00eecf19dcea48592ef1f7688eefc"
dependencies = [
"cranelift-codegen",
"log",
@@ -110,15 +124,15 @@ dependencies = [
[[package]]
name = "cranelift-isle"
-version = "0.87.0"
+version = "0.88.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d51089478849f2ac8ef60a8a2d5346c8d4abfec0e45ac5b24530ef9f9499e1e"
+checksum = "3be64cecea9d90105fc6a2ba2d003e98c867c1d6c4c86cc878f97ad9fb916293"
[[package]]
name = "cranelift-jit"
-version = "0.87.0"
+version = "0.88.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "095936e41720f86004b4c57ce88e6a13af28646bb3a6fb4afbebd5ae90c50029"
+checksum = "f98ed42a70a0c9c388e34ec9477f57fc7300f541b1e5136a0e2ea02b1fac6015"
dependencies = [
"anyhow",
"cranelift-codegen",
@@ -134,9 +148,9 @@ dependencies = [
[[package]]
name = "cranelift-module"
-version = "0.87.0"
+version = "0.88.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "704a1aea4723d97eafe0fb7af110f6f6868b1ac95f5380bbc9adb2a3b8cf97e8"
+checksum = "d658ac7f156708bfccb647216cc8b9387469f50d352ba4ad80150541e4ae2d49"
dependencies = [
"anyhow",
"cranelift-codegen",
@@ -144,9 +158,9 @@ dependencies = [
[[package]]
name = "cranelift-native"
-version = "0.87.0"
+version = "0.88.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "885debe62f2078638d6585f54c9f05f5c2008f22ce5a2a9100ada785fc065dbd"
+checksum = "c4a03a6ac1b063e416ca4b93f6247978c991475e8271465340caa6f92f3c16a4"
dependencies = [
"cranelift-codegen",
"libc",
@@ -155,9 +169,9 @@ dependencies = [
[[package]]
name = "cranelift-object"
-version = "0.87.0"
+version = "0.88.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aac1310cf1081ae8eca916c92cd163b977c77cab6e831fa812273c26ff921816"
+checksum = "eef0b4119b645b870a43a036d76c0ada3a076b1f82e8b8487659304c8b09049b"
dependencies = [
"anyhow",
"cranelift-codegen",
@@ -232,9 +246,9 @@ checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b"
[[package]]
name = "libloading"
-version = "0.6.7"
+version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883"
+checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
dependencies = [
"cfg-if",
"winapi",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index e7c342748..09cf5b4a1 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -8,19 +8,19 @@ crate-type = ["dylib"]
[dependencies]
# These have to be in sync with each other
-cranelift-codegen = { version = "0.87.0", features = ["unwind", "all-arch"] }
-cranelift-frontend = "0.87.0"
-cranelift-module = "0.87.0"
-cranelift-native = "0.87.0"
-cranelift-jit = { version = "0.87.0", optional = true }
-cranelift-object = "0.87.0"
+cranelift-codegen = { version = "0.88.1", features = ["unwind", "all-arch"] }
+cranelift-frontend = "0.88.1"
+cranelift-module = "0.88.1"
+cranelift-native = "0.88.1"
+cranelift-jit = { version = "0.88.1", optional = true }
+cranelift-object = "0.88.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"] }
ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
indexmap = "1.9.1"
-libloading = { version = "0.6.0", optional = true }
+libloading = { version = "0.7.3", optional = true }
once_cell = "1.10.0"
smallvec = "1.8.1"
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
index 6c5043bb6..f6a9cb672 100644
--- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
@@ -55,10 +55,20 @@ dependencies = [
]
[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+dependencies = [
+ "compiler_builtins",
+ "rustc-std-workspace-core",
+]
+
+[[package]]
name = "compiler_builtins"
-version = "0.1.79"
+version = "0.1.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f873ce2bd3550b0b565f878b3d04ea8253f4259dc3d20223af2e1ba86f5ecca"
+checksum = "18cd7635fea7bb481ea543b392789844c1ad581299da70184c7175ce3af76603"
dependencies = [
"rustc-std-workspace-core",
]
@@ -123,9 +133,9 @@ dependencies = [
[[package]]
name = "hermit-abi"
-version = "0.2.5"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "897cd85af6387be149f55acf168e41be176a02de7872403aaab184afc2f327e6"
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"compiler_builtins",
"libc",
@@ -135,9 +145,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.132"
+version = "0.2.135"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
+checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
dependencies = [
"rustc-std-workspace-core",
]
@@ -182,7 +192,7 @@ name = "panic_abort"
version = "0.0.0"
dependencies = [
"alloc",
- "cfg-if",
+ "cfg-if 0.1.10",
"compiler_builtins",
"core",
"libc",
@@ -193,7 +203,7 @@ name = "panic_unwind"
version = "0.0.0"
dependencies = [
"alloc",
- "cfg-if",
+ "cfg-if 0.1.10",
"compiler_builtins",
"core",
"libc",
@@ -245,7 +255,7 @@ version = "0.0.0"
dependencies = [
"addr2line",
"alloc",
- "cfg-if",
+ "cfg-if 1.0.0",
"compiler_builtins",
"core",
"dlmalloc",
@@ -267,7 +277,7 @@ dependencies = [
name = "std_detect"
version = "0.1.5"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
"compiler_builtins",
"libc",
"rustc-std-workspace-alloc",
@@ -289,7 +299,7 @@ dependencies = [
name = "test"
version = "0.0.0"
dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
"core",
"getopts",
"libc",
@@ -301,9 +311,9 @@ dependencies = [
[[package]]
name = "unicode-width"
-version = "0.1.9"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
@@ -315,7 +325,7 @@ name = "unwind"
version = "0.0.0"
dependencies = [
"cc",
- "cfg-if",
+ "cfg-if 0.1.10",
"compiler_builtins",
"core",
"libc",
diff --git a/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs
new file mode 100644
index 000000000..fae5b2716
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/build_system/abi_cafe.rs
@@ -0,0 +1,52 @@
+use std::env;
+use std::path::Path;
+
+use super::build_sysroot;
+use super::config;
+use super::prepare;
+use super::utils::{cargo_command, spawn_and_wait};
+use super::SysrootKind;
+
+pub(crate) fn run(
+ channel: &str,
+ sysroot_kind: SysrootKind,
+ target_dir: &Path,
+ cg_clif_dylib: &Path,
+ host_triple: &str,
+ target_triple: &str,
+) {
+ if !config::get_bool("testsuite.abi-cafe") {
+ eprintln!("[SKIP] abi-cafe");
+ return;
+ }
+
+ if host_triple != target_triple {
+ eprintln!("[SKIP] abi-cafe (cross-compilation not supported)");
+ return;
+ }
+
+ eprintln!("Building sysroot for abi-cafe");
+ build_sysroot::build_sysroot(
+ channel,
+ sysroot_kind,
+ target_dir,
+ cg_clif_dylib,
+ host_triple,
+ target_triple,
+ );
+
+ eprintln!("Running abi-cafe");
+ let abi_cafe_path = prepare::ABI_CAFE.source_dir();
+ env::set_current_dir(abi_cafe_path.clone()).unwrap();
+
+ let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"];
+
+ let mut cmd = cargo_command("cargo", "run", Some(target_triple), &abi_cafe_path);
+ cmd.arg("--");
+ cmd.arg("--pairs");
+ cmd.args(pairs);
+ cmd.arg("--add-rustc-codegen-backend");
+ cmd.arg(format!("cgclif:{}", cg_clif_dylib.display()));
+
+ spawn_and_wait(cmd);
+}
diff --git a/compiler/rustc_codegen_cranelift/build_system/abi_checker.rs b/compiler/rustc_codegen_cranelift/build_system/abi_checker.rs
deleted file mode 100644
index 67dbd0a38..000000000
--- a/compiler/rustc_codegen_cranelift/build_system/abi_checker.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-use super::build_sysroot;
-use super::config;
-use super::utils::spawn_and_wait;
-use build_system::SysrootKind;
-use std::env;
-use std::path::Path;
-use std::process::Command;
-
-pub(crate) fn run(
- channel: &str,
- sysroot_kind: SysrootKind,
- target_dir: &Path,
- cg_clif_build_dir: &Path,
- host_triple: &str,
- target_triple: &str,
-) {
- if !config::get_bool("testsuite.abi-checker") {
- eprintln!("[SKIP] abi-checker");
- return;
- }
-
- if host_triple != target_triple {
- eprintln!("[SKIP] abi-checker (cross-compilation not supported)");
- return;
- }
-
- eprintln!("Building sysroot for abi-checker");
- build_sysroot::build_sysroot(
- channel,
- sysroot_kind,
- target_dir,
- cg_clif_build_dir,
- host_triple,
- target_triple,
- );
-
- eprintln!("Running abi-checker");
- let mut abi_checker_path = env::current_dir().unwrap();
- abi_checker_path.push("abi-checker");
- env::set_current_dir(abi_checker_path.clone()).unwrap();
-
- let build_dir = abi_checker_path.parent().unwrap().join("build");
- let cg_clif_dylib_path = build_dir.join(if cfg!(windows) { "bin" } else { "lib" }).join(
- env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
- );
-
- let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"];
-
- let mut cmd = Command::new("cargo");
- cmd.arg("run");
- cmd.arg("--target");
- cmd.arg(target_triple);
- cmd.arg("--");
- cmd.arg("--pairs");
- cmd.args(pairs);
- cmd.arg("--add-rustc-codegen-backend");
- cmd.arg(format!("cgclif:{}", cg_clif_dylib_path.display()));
-
- spawn_and_wait(cmd);
-}
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
index 9e59b8199..cda468bcf 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
@@ -1,16 +1,16 @@
use std::env;
-use std::path::{Path, PathBuf};
-use std::process::Command;
+use std::path::PathBuf;
-use super::utils::is_ci;
+use super::rustc_info::get_file_name;
+use super::utils::{cargo_command, is_ci};
pub(crate) fn build_backend(
channel: &str,
host_triple: &str,
use_unstable_features: bool,
) -> PathBuf {
- let mut cmd = Command::new("cargo");
- cmd.arg("build").arg("--target").arg(host_triple);
+ let source_dir = std::env::current_dir().unwrap();
+ let mut cmd = cargo_command("cargo", "build", Some(host_triple), &source_dir);
cmd.env("CARGO_BUILD_INCREMENTAL", "true"); // Force incr comp even in release mode
@@ -41,5 +41,9 @@ pub(crate) fn build_backend(
eprintln!("[BUILD] rustc_codegen_cranelift");
super::utils::spawn_and_wait(cmd);
- Path::new("target").join(host_triple).join(channel)
+ source_dir
+ .join("target")
+ .join(host_triple)
+ .join(channel)
+ .join(get_file_name("rustc_codegen_cranelift", "dylib"))
}
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
index 7e205b0fd..856aecc49 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
@@ -3,14 +3,14 @@ use std::path::{Path, PathBuf};
use std::process::{self, Command};
use super::rustc_info::{get_file_name, get_rustc_version, get_wrapper_file_name};
-use super::utils::{spawn_and_wait, try_hard_link};
+use super::utils::{cargo_command, spawn_and_wait, try_hard_link};
use super::SysrootKind;
pub(crate) fn build_sysroot(
channel: &str,
sysroot_kind: SysrootKind,
target_dir: &Path,
- cg_clif_build_dir: &Path,
+ cg_clif_dylib_src: &Path,
host_triple: &str,
target_triple: &str,
) {
@@ -23,7 +23,6 @@ pub(crate) fn build_sysroot(
fs::create_dir_all(target_dir.join("lib")).unwrap();
// Copy the backend
- let cg_clif_dylib = get_file_name("rustc_codegen_cranelift", "dylib");
let cg_clif_dylib_path = target_dir
.join(if cfg!(windows) {
// Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
@@ -32,8 +31,8 @@ pub(crate) fn build_sysroot(
} else {
"lib"
})
- .join(&cg_clif_dylib);
- try_hard_link(cg_clif_build_dir.join(cg_clif_dylib), &cg_clif_dylib_path);
+ .join(get_file_name("rustc_codegen_cranelift", "dylib"));
+ try_hard_link(cg_clif_dylib_src, &cg_clif_dylib_path);
// Build and copy rustc and cargo wrappers
for wrapper in ["rustc-clif", "cargo-clif"] {
@@ -186,10 +185,10 @@ fn build_clif_sysroot_for_triple(
}
// Build sysroot
- let mut build_cmd = Command::new("cargo");
- build_cmd.arg("build").arg("--target").arg(triple).current_dir("build_sysroot");
+ let mut build_cmd = cargo_command("cargo", "build", Some(triple), Path::new("build_sysroot"));
let mut rustflags = "-Zforce-unstable-if-unmarked -Cpanic=abort".to_string();
rustflags.push_str(&format!(" -Zcodegen-backend={}", cg_clif_dylib_path.to_str().unwrap()));
+ rustflags.push_str(&format!(" --sysroot={}", target_dir.to_str().unwrap()));
if channel == "release" {
build_cmd.arg("--release");
rustflags.push_str(" -Zmir-opt-level=3");
diff --git a/compiler/rustc_codegen_cranelift/build_system/config.rs b/compiler/rustc_codegen_cranelift/build_system/config.rs
index ef540cf1f..c31784e10 100644
--- a/compiler/rustc_codegen_cranelift/build_system/config.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/config.rs
@@ -1,4 +1,5 @@
-use std::{fs, process};
+use std::fs;
+use std::process;
fn load_config_file() -> Vec<(String, Option<String>)> {
fs::read_to_string("config.txt")
diff --git a/compiler/rustc_codegen_cranelift/build_system/mod.rs b/compiler/rustc_codegen_cranelift/build_system/mod.rs
index c3706dc6f..b25270d83 100644
--- a/compiler/rustc_codegen_cranelift/build_system/mod.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/mod.rs
@@ -4,7 +4,7 @@ use std::process;
use self::utils::is_ci;
-mod abi_checker;
+mod abi_cafe;
mod build_backend;
mod build_sysroot;
mod config;
@@ -122,32 +122,23 @@ pub fn main() {
host_triple.clone()
};
- if target_triple.ends_with("-msvc") {
- eprintln!("The MSVC toolchain is not yet supported by rustc_codegen_cranelift.");
- eprintln!("Switch to the MinGW toolchain for Windows support.");
- eprintln!("Hint: You can use `rustup set default-host x86_64-pc-windows-gnu` to");
- eprintln!("set the global default target to MinGW");
- process::exit(1);
- }
-
- let cg_clif_build_dir =
- build_backend::build_backend(channel, &host_triple, use_unstable_features);
+ let cg_clif_dylib = build_backend::build_backend(channel, &host_triple, use_unstable_features);
match command {
Command::Test => {
tests::run_tests(
channel,
sysroot_kind,
&target_dir,
- &cg_clif_build_dir,
+ &cg_clif_dylib,
&host_triple,
&target_triple,
);
- abi_checker::run(
+ abi_cafe::run(
channel,
sysroot_kind,
&target_dir,
- &cg_clif_build_dir,
+ &cg_clif_dylib,
&host_triple,
&target_triple,
);
@@ -157,7 +148,7 @@ pub fn main() {
channel,
sysroot_kind,
&target_dir,
- &cg_clif_build_dir,
+ &cg_clif_dylib,
&host_triple,
&target_triple,
);
diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
index d23b7f00d..3111f62f6 100644
--- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
@@ -1,64 +1,63 @@
use std::env;
use std::ffi::OsStr;
-use std::ffi::OsString;
use std::fs;
-use std::path::Path;
+use std::path::{Path, PathBuf};
use std::process::Command;
use super::rustc_info::{get_file_name, get_rustc_path, get_rustc_version};
-use super::utils::{copy_dir_recursively, spawn_and_wait};
+use super::utils::{cargo_command, copy_dir_recursively, spawn_and_wait};
+
+pub(crate) const ABI_CAFE: GitRepo =
+ GitRepo::github("Gankra", "abi-cafe", "4c6dc8c9c687e2b3a760ff2176ce236872b37212", "abi-cafe");
+
+pub(crate) const RAND: GitRepo =
+ GitRepo::github("rust-random", "rand", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", "rand");
+
+pub(crate) const REGEX: GitRepo =
+ GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex");
+
+pub(crate) const PORTABLE_SIMD: GitRepo = GitRepo::github(
+ "rust-lang",
+ "portable-simd",
+ "d5cd4a8112d958bd3a252327e0d069a6363249bd",
+ "portable-simd",
+);
+
+pub(crate) const SIMPLE_RAYTRACER: GitRepo = GitRepo::github(
+ "ebobby",
+ "simple-raytracer",
+ "804a7a21b9e673a482797aa289a18ed480e4d813",
+ "<none>",
+);
pub(crate) fn prepare() {
+ if Path::new("download").exists() {
+ std::fs::remove_dir_all(Path::new("download")).unwrap();
+ }
+ std::fs::create_dir_all(Path::new("download")).unwrap();
+
prepare_sysroot();
+ // FIXME maybe install this only locally?
eprintln!("[INSTALL] hyperfine");
Command::new("cargo").arg("install").arg("hyperfine").spawn().unwrap().wait().unwrap();
- clone_repo_shallow_github(
- "abi-checker",
- "Gankra",
- "abi-checker",
- "a2232d45f202846f5c02203c9f27355360f9a2ff",
- );
- apply_patches("abi-checker", Path::new("abi-checker"));
-
- clone_repo_shallow_github(
- "rand",
- "rust-random",
- "rand",
- "0f933f9c7176e53b2a3c7952ded484e1783f0bf1",
- );
- apply_patches("rand", Path::new("rand"));
-
- clone_repo_shallow_github(
- "regex",
- "rust-lang",
- "regex",
- "341f207c1071f7290e3f228c710817c280c8dca1",
- );
-
- clone_repo_shallow_github(
- "portable-simd",
- "rust-lang",
- "portable-simd",
- "b8d6b6844602f80af79cd96401339ec594d472d8",
- );
- apply_patches("portable-simd", Path::new("portable-simd"));
-
- clone_repo_shallow_github(
- "simple-raytracer",
- "ebobby",
- "simple-raytracer",
- "804a7a21b9e673a482797aa289a18ed480e4d813",
- );
+ ABI_CAFE.fetch();
+ RAND.fetch();
+ REGEX.fetch();
+ PORTABLE_SIMD.fetch();
+ SIMPLE_RAYTRACER.fetch();
eprintln!("[LLVM BUILD] simple-raytracer");
- let mut build_cmd = Command::new("cargo");
- build_cmd.arg("build").env_remove("CARGO_TARGET_DIR").current_dir("simple-raytracer");
+ let build_cmd = cargo_command("cargo", "build", None, &SIMPLE_RAYTRACER.source_dir());
spawn_and_wait(build_cmd);
fs::copy(
- Path::new("simple-raytracer/target/debug").join(get_file_name("main", "bin")),
- Path::new("simple-raytracer").join(get_file_name("raytracer_cg_llvm", "bin")),
+ SIMPLE_RAYTRACER
+ .source_dir()
+ .join("target")
+ .join("debug")
+ .join(get_file_name("main", "bin")),
+ SIMPLE_RAYTRACER.source_dir().join(get_file_name("raytracer_cg_llvm", "bin")),
)
.unwrap();
}
@@ -90,38 +89,78 @@ fn prepare_sysroot() {
apply_patches("sysroot", &sysroot_src);
}
+pub(crate) struct GitRepo {
+ url: GitRepoUrl,
+ rev: &'static str,
+ patch_name: &'static str,
+}
+
+enum GitRepoUrl {
+ Github { user: &'static str, repo: &'static str },
+}
+
+impl GitRepo {
+ const fn github(
+ user: &'static str,
+ repo: &'static str,
+ rev: &'static str,
+ patch_name: &'static str,
+ ) -> GitRepo {
+ GitRepo { url: GitRepoUrl::Github { user, repo }, rev, patch_name }
+ }
+
+ pub(crate) fn source_dir(&self) -> PathBuf {
+ match self.url {
+ GitRepoUrl::Github { user: _, repo } => {
+ std::env::current_dir().unwrap().join("download").join(repo)
+ }
+ }
+ }
+
+ fn fetch(&self) {
+ match self.url {
+ GitRepoUrl::Github { user, repo } => {
+ clone_repo_shallow_github(&self.source_dir(), user, repo, self.rev);
+ }
+ }
+ apply_patches(self.patch_name, &self.source_dir());
+ }
+}
+
#[allow(dead_code)]
-fn clone_repo(target_dir: &str, repo: &str, rev: &str) {
+fn clone_repo(download_dir: &Path, repo: &str, rev: &str) {
eprintln!("[CLONE] {}", repo);
// Ignore exit code as the repo may already have been checked out
- Command::new("git").arg("clone").arg(repo).arg(target_dir).spawn().unwrap().wait().unwrap();
+ Command::new("git").arg("clone").arg(repo).arg(&download_dir).spawn().unwrap().wait().unwrap();
let mut clean_cmd = Command::new("git");
- clean_cmd.arg("checkout").arg("--").arg(".").current_dir(target_dir);
+ clean_cmd.arg("checkout").arg("--").arg(".").current_dir(&download_dir);
spawn_and_wait(clean_cmd);
let mut checkout_cmd = Command::new("git");
- checkout_cmd.arg("checkout").arg("-q").arg(rev).current_dir(target_dir);
+ checkout_cmd.arg("checkout").arg("-q").arg(rev).current_dir(download_dir);
spawn_and_wait(checkout_cmd);
}
-fn clone_repo_shallow_github(target_dir: &str, username: &str, repo: &str, rev: &str) {
+fn clone_repo_shallow_github(download_dir: &Path, user: &str, repo: &str, rev: &str) {
if cfg!(windows) {
// Older windows doesn't have tar or curl by default. Fall back to using git.
- clone_repo(target_dir, &format!("https://github.com/{}/{}.git", username, repo), rev);
+ clone_repo(download_dir, &format!("https://github.com/{}/{}.git", user, repo), rev);
return;
}
- let archive_url = format!("https://github.com/{}/{}/archive/{}.tar.gz", username, repo, rev);
- let archive_file = format!("{}.tar.gz", rev);
- let archive_dir = format!("{}-{}", repo, rev);
+ let downloads_dir = std::env::current_dir().unwrap().join("download");
+
+ let archive_url = format!("https://github.com/{}/{}/archive/{}.tar.gz", user, repo, rev);
+ let archive_file = downloads_dir.join(format!("{}.tar.gz", rev));
+ let archive_dir = downloads_dir.join(format!("{}-{}", repo, rev));
- eprintln!("[DOWNLOAD] {}/{} from {}", username, repo, archive_url);
+ eprintln!("[DOWNLOAD] {}/{} from {}", user, repo, archive_url);
// Remove previous results if they exists
let _ = std::fs::remove_file(&archive_file);
let _ = std::fs::remove_dir_all(&archive_dir);
- let _ = std::fs::remove_dir_all(target_dir);
+ let _ = std::fs::remove_dir_all(&download_dir);
// Download zip archive
let mut download_cmd = Command::new("curl");
@@ -130,13 +169,13 @@ fn clone_repo_shallow_github(target_dir: &str, username: &str, repo: &str, rev:
// Unpack tar archive
let mut unpack_cmd = Command::new("tar");
- unpack_cmd.arg("xf").arg(&archive_file);
+ unpack_cmd.arg("xf").arg(&archive_file).current_dir(downloads_dir);
spawn_and_wait(unpack_cmd);
// Rename unpacked dir to the expected name
- std::fs::rename(archive_dir, target_dir).unwrap();
+ std::fs::rename(archive_dir, &download_dir).unwrap();
- init_git_repo(Path::new(target_dir));
+ init_git_repo(&download_dir);
// Cleanup
std::fs::remove_file(archive_file).unwrap();
@@ -156,14 +195,20 @@ fn init_git_repo(repo_dir: &Path) {
spawn_and_wait(git_commit_cmd);
}
-fn get_patches(crate_name: &str) -> Vec<OsString> {
- let mut patches: Vec<_> = fs::read_dir("patches")
+fn get_patches(source_dir: &Path, crate_name: &str) -> Vec<PathBuf> {
+ let mut patches: Vec<_> = fs::read_dir(source_dir.join("patches"))
.unwrap()
.map(|entry| entry.unwrap().path())
.filter(|path| path.extension() == Some(OsStr::new("patch")))
- .map(|path| path.file_name().unwrap().to_owned())
- .filter(|file_name| {
- file_name.to_str().unwrap().split_once("-").unwrap().1.starts_with(crate_name)
+ .filter(|path| {
+ path.file_name()
+ .unwrap()
+ .to_str()
+ .unwrap()
+ .split_once("-")
+ .unwrap()
+ .1
+ .starts_with(crate_name)
})
.collect();
patches.sort();
@@ -171,11 +216,18 @@ fn get_patches(crate_name: &str) -> Vec<OsString> {
}
fn apply_patches(crate_name: &str, target_dir: &Path) {
- for patch in get_patches(crate_name) {
- eprintln!("[PATCH] {:?} <- {:?}", target_dir.file_name().unwrap(), patch);
- let patch_arg = env::current_dir().unwrap().join("patches").join(patch);
+ if crate_name == "<none>" {
+ return;
+ }
+
+ for patch in get_patches(&std::env::current_dir().unwrap(), crate_name) {
+ eprintln!(
+ "[PATCH] {:?} <- {:?}",
+ target_dir.file_name().unwrap(),
+ patch.file_name().unwrap()
+ );
let mut apply_patch_cmd = Command::new("git");
- apply_patch_cmd.arg("am").arg(patch_arg).arg("-q").current_dir(target_dir);
+ apply_patch_cmd.arg("am").arg(patch).arg("-q").current_dir(target_dir);
spawn_and_wait(apply_patch_cmd);
}
}
diff --git a/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs b/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs
index 913b589af..3c08b6fa3 100644
--- a/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/rustc_info.rs
@@ -65,7 +65,7 @@ pub(crate) fn get_file_name(crate_name: &str, crate_type: &str) -> String {
}
/// Similar to `get_file_name`, but converts any dashes (`-`) in the `crate_name` to
-/// underscores (`_`). This is specially made for the the rustc and cargo wrappers
+/// underscores (`_`). This is specially made for the rustc and cargo wrappers
/// which have a dash in the name, and that is not allowed in a crate name.
pub(crate) fn get_wrapper_file_name(crate_name: &str, crate_type: &str) -> String {
let crate_name = crate_name.replace('-', "_");
diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs
index e21397cec..a414b60f4 100644
--- a/compiler/rustc_codegen_cranelift/build_system/tests.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs
@@ -1,7 +1,8 @@
use super::build_sysroot;
use super::config;
+use super::prepare;
use super::rustc_info::get_wrapper_file_name;
-use super::utils::{spawn_and_wait, spawn_and_wait_with_input};
+use super::utils::{cargo_command, hyperfine_command, spawn_and_wait, spawn_and_wait_with_input};
use build_system::SysrootKind;
use std::env;
use std::ffi::OsStr;
@@ -217,103 +218,95 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
TestCase::new("test.rust-random/rand", &|runner| {
- runner.in_dir(["rand"], |runner| {
- runner.run_cargo(["clean"]);
+ runner.in_dir(prepare::RAND.source_dir(), |runner| {
+ runner.run_cargo("clean", []);
if runner.host_triple == runner.target_triple {
eprintln!("[TEST] rust-random/rand");
- runner.run_cargo(["test", "--workspace"]);
+ runner.run_cargo("test", ["--workspace"]);
} else {
eprintln!("[AOT] rust-random/rand");
- runner.run_cargo([
- "build",
- "--workspace",
- "--target",
- &runner.target_triple,
- "--tests",
- ]);
+ runner.run_cargo("build", ["--workspace", "--tests"]);
}
});
}),
TestCase::new("bench.simple-raytracer", &|runner| {
- runner.in_dir(["simple-raytracer"], |runner| {
- let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string());
+ runner.in_dir(prepare::SIMPLE_RAYTRACER.source_dir(), |runner| {
+ let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string()).parse().unwrap();
if runner.host_triple == runner.target_triple {
eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
- let mut bench_compile = Command::new("hyperfine");
- bench_compile.arg("--runs");
- bench_compile.arg(&run_runs);
- bench_compile.arg("--warmup");
- bench_compile.arg("1");
- bench_compile.arg("--prepare");
- bench_compile.arg(format!("{:?}", runner.cargo_command(["clean"])));
-
- if cfg!(windows) {
- bench_compile.arg("cmd /C \"set RUSTFLAGS= && cargo build\"");
- } else {
- bench_compile.arg("RUSTFLAGS='' cargo build");
- }
+ let prepare = runner.cargo_command("clean", []);
+
+ let llvm_build_cmd = cargo_command("cargo", "build", None, Path::new("."));
+
+ let cargo_clif = runner
+ .root_dir
+ .clone()
+ .join("build")
+ .join(get_wrapper_file_name("cargo-clif", "bin"));
+ let clif_build_cmd = cargo_command(cargo_clif, "build", None, Path::new("."));
+
+ let bench_compile =
+ hyperfine_command(1, run_runs, Some(prepare), llvm_build_cmd, clif_build_cmd);
- bench_compile.arg(format!("{:?}", runner.cargo_command(["build"])));
spawn_and_wait(bench_compile);
eprintln!("[BENCH RUN] ebobby/simple-raytracer");
fs::copy(PathBuf::from("./target/debug/main"), PathBuf::from("raytracer_cg_clif"))
.unwrap();
- let mut bench_run = Command::new("hyperfine");
- bench_run.arg("--runs");
- bench_run.arg(&run_runs);
- bench_run.arg(PathBuf::from("./raytracer_cg_llvm"));
- bench_run.arg(PathBuf::from("./raytracer_cg_clif"));
+ let bench_run = hyperfine_command(
+ 0,
+ run_runs,
+ None,
+ Command::new("./raytracer_cg_llvm"),
+ Command::new("./raytracer_cg_clif"),
+ );
spawn_and_wait(bench_run);
} else {
- runner.run_cargo(["clean"]);
+ runner.run_cargo("clean", []);
eprintln!("[BENCH COMPILE] ebobby/simple-raytracer (skipped)");
eprintln!("[COMPILE] ebobby/simple-raytracer");
- runner.run_cargo(["build", "--target", &runner.target_triple]);
+ runner.run_cargo("build", []);
eprintln!("[BENCH RUN] ebobby/simple-raytracer (skipped)");
}
});
}),
TestCase::new("test.libcore", &|runner| {
- runner.in_dir(["build_sysroot", "sysroot_src", "library", "core", "tests"], |runner| {
- runner.run_cargo(["clean"]);
-
- if runner.host_triple == runner.target_triple {
- runner.run_cargo(["test"]);
- } else {
- eprintln!("Cross-Compiling: Not running tests");
- runner.run_cargo(["build", "--target", &runner.target_triple, "--tests"]);
- }
- });
+ runner.in_dir(
+ std::env::current_dir()
+ .unwrap()
+ .join("build_sysroot")
+ .join("sysroot_src")
+ .join("library")
+ .join("core")
+ .join("tests"),
+ |runner| {
+ runner.run_cargo("clean", []);
+
+ if runner.host_triple == runner.target_triple {
+ runner.run_cargo("test", []);
+ } else {
+ eprintln!("Cross-Compiling: Not running tests");
+ runner.run_cargo("build", ["--tests"]);
+ }
+ },
+ );
}),
TestCase::new("test.regex-shootout-regex-dna", &|runner| {
- runner.in_dir(["regex"], |runner| {
- runner.run_cargo(["clean"]);
+ runner.in_dir(prepare::REGEX.source_dir(), |runner| {
+ runner.run_cargo("clean", []);
// newer aho_corasick versions throw a deprecation warning
let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
- let mut build_cmd = runner.cargo_command([
- "build",
- "--example",
- "shootout-regex-dna",
- "--target",
- &runner.target_triple,
- ]);
+ let mut build_cmd = runner.cargo_command("build", ["--example", "shootout-regex-dna"]);
build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
spawn_and_wait(build_cmd);
if runner.host_triple == runner.target_triple {
- let mut run_cmd = runner.cargo_command([
- "run",
- "--example",
- "shootout-regex-dna",
- "--target",
- &runner.target_triple,
- ]);
+ let mut run_cmd = runner.cargo_command("run", ["--example", "shootout-regex-dna"]);
run_cmd.env("RUSTFLAGS", lint_rust_flags);
let input =
@@ -353,41 +346,43 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
});
}),
TestCase::new("test.regex", &|runner| {
- runner.in_dir(["regex"], |runner| {
- runner.run_cargo(["clean"]);
+ runner.in_dir(prepare::REGEX.source_dir(), |runner| {
+ runner.run_cargo("clean", []);
// newer aho_corasick versions throw a deprecation warning
let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
if runner.host_triple == runner.target_triple {
- let mut run_cmd = runner.cargo_command([
+ let mut run_cmd = runner.cargo_command(
"test",
- "--tests",
- "--",
- "--exclude-should-panic",
- "--test-threads",
- "1",
- "-Zunstable-options",
- "-q",
- ]);
+ [
+ "--tests",
+ "--",
+ "--exclude-should-panic",
+ "--test-threads",
+ "1",
+ "-Zunstable-options",
+ "-q",
+ ],
+ );
run_cmd.env("RUSTFLAGS", lint_rust_flags);
spawn_and_wait(run_cmd);
} else {
eprintln!("Cross-Compiling: Not running tests");
let mut build_cmd =
- runner.cargo_command(["build", "--tests", "--target", &runner.target_triple]);
+ runner.cargo_command("build", ["--tests", "--target", &runner.target_triple]);
build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
spawn_and_wait(build_cmd);
}
});
}),
TestCase::new("test.portable-simd", &|runner| {
- runner.in_dir(["portable-simd"], |runner| {
- runner.run_cargo(["clean"]);
- runner.run_cargo(["build", "--all-targets", "--target", &runner.target_triple]);
+ runner.in_dir(prepare::PORTABLE_SIMD.source_dir(), |runner| {
+ runner.run_cargo("clean", []);
+ runner.run_cargo("build", ["--all-targets", "--target", &runner.target_triple]);
if runner.host_triple == runner.target_triple {
- runner.run_cargo(["test", "-q"]);
+ runner.run_cargo("test", ["-q"]);
}
});
}),
@@ -397,7 +392,7 @@ pub(crate) fn run_tests(
channel: &str,
sysroot_kind: SysrootKind,
target_dir: &Path,
- cg_clif_build_dir: &Path,
+ cg_clif_dylib: &Path,
host_triple: &str,
target_triple: &str,
) {
@@ -408,7 +403,7 @@ pub(crate) fn run_tests(
channel,
SysrootKind::None,
&target_dir,
- cg_clif_build_dir,
+ cg_clif_dylib,
&host_triple,
&target_triple,
);
@@ -427,7 +422,7 @@ pub(crate) fn run_tests(
channel,
sysroot_kind,
&target_dir,
- cg_clif_build_dir,
+ cg_clif_dylib,
&host_triple,
&target_triple,
);
@@ -521,16 +516,8 @@ impl TestRunner {
}
}
- fn in_dir<'a, I, F>(&self, dir: I, callback: F)
- where
- I: IntoIterator<Item = &'a str>,
- F: FnOnce(&TestRunner),
- {
+ fn in_dir(&self, new: impl AsRef<Path>, callback: impl FnOnce(&TestRunner)) {
let current = env::current_dir().unwrap();
- let mut new = current.clone();
- for d in dir {
- new.push(d);
- }
env::set_current_dir(new).unwrap();
callback(self);
@@ -595,25 +582,29 @@ impl TestRunner {
spawn_and_wait(cmd);
}
- fn cargo_command<I, S>(&self, args: I) -> Command
+ fn cargo_command<'a, I>(&self, subcommand: &str, args: I) -> Command
where
- I: IntoIterator<Item = S>,
- S: AsRef<OsStr>,
+ I: IntoIterator<Item = &'a str>,
{
let mut cargo_clif = self.root_dir.clone();
cargo_clif.push("build");
cargo_clif.push(get_wrapper_file_name("cargo-clif", "bin"));
- let mut cmd = Command::new(cargo_clif);
+ let mut cmd = cargo_command(
+ cargo_clif,
+ subcommand,
+ if subcommand == "clean" { None } else { Some(&self.target_triple) },
+ Path::new("."),
+ );
cmd.args(args);
cmd.env("RUSTFLAGS", &self.rust_flags);
cmd
}
- fn run_cargo<'a, I>(&self, args: I)
+ fn run_cargo<'a, I>(&self, subcommand: &str, args: I)
where
I: IntoIterator<Item = &'a str>,
{
- spawn_and_wait(self.cargo_command(args));
+ spawn_and_wait(self.cargo_command(subcommand, args));
}
}
diff --git a/compiler/rustc_codegen_cranelift/build_system/utils.rs b/compiler/rustc_codegen_cranelift/build_system/utils.rs
index bdf8f8ecd..48da64906 100644
--- a/compiler/rustc_codegen_cranelift/build_system/utils.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/utils.rs
@@ -4,6 +4,52 @@ use std::io::Write;
use std::path::Path;
use std::process::{self, Command, Stdio};
+pub(crate) fn cargo_command(
+ cargo: impl AsRef<Path>,
+ subcommand: &str,
+ triple: Option<&str>,
+ source_dir: &Path,
+) -> Command {
+ let mut cmd = Command::new(cargo.as_ref());
+ cmd.arg(subcommand)
+ .arg("--manifest-path")
+ .arg(source_dir.join("Cargo.toml"))
+ .arg("--target-dir")
+ .arg(source_dir.join("target"));
+
+ if let Some(triple) = triple {
+ cmd.arg("--target").arg(triple);
+ }
+
+ cmd
+}
+
+pub(crate) fn hyperfine_command(
+ warmup: u64,
+ runs: u64,
+ prepare: Option<Command>,
+ a: Command,
+ b: Command,
+) -> Command {
+ let mut bench = Command::new("hyperfine");
+
+ if warmup != 0 {
+ bench.arg("--warmup").arg(warmup.to_string());
+ }
+
+ if runs != 0 {
+ bench.arg("--runs").arg(runs.to_string());
+ }
+
+ if let Some(prepare) = prepare {
+ bench.arg("--prepare").arg(format!("{:?}", prepare));
+ }
+
+ bench.arg(format!("{:?}", a)).arg(format!("{:?}", b));
+
+ bench
+}
+
#[track_caller]
pub(crate) fn try_hard_link(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
let src = src.as_ref();
diff --git a/compiler/rustc_codegen_cranelift/clean_all.sh b/compiler/rustc_codegen_cranelift/clean_all.sh
index 62e52bd19..fedab2433 100755
--- a/compiler/rustc_codegen_cranelift/clean_all.sh
+++ b/compiler/rustc_codegen_cranelift/clean_all.sh
@@ -3,4 +3,8 @@ set -e
rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
rm -rf target/ build/ perf.data{,.old} y.bin
-rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/
+rm -rf download/
+
+# Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh
+# FIXME remove at some point in the future
+rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/ abi-cafe/
diff --git a/compiler/rustc_codegen_cranelift/config.txt b/compiler/rustc_codegen_cranelift/config.txt
index 2264d301d..0d539191b 100644
--- a/compiler/rustc_codegen_cranelift/config.txt
+++ b/compiler/rustc_codegen_cranelift/config.txt
@@ -49,4 +49,4 @@ test.regex-shootout-regex-dna
test.regex
test.portable-simd
-testsuite.abi-checker
+testsuite.abi-cafe
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 2ecc8b823..039100696 100644
--- a/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs
+++ b/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs
@@ -5,7 +5,6 @@
// Test that we can handle unsized types with an extern type tail part.
// Regression test for issue #91827.
-#![feature(const_ptr_offset_from)]
#![feature(extern_types)]
use std::ptr::addr_of;
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 42f8aa50b..7f85b52f0 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -559,16 +559,22 @@ pub union MaybeUninit<T> {
pub mod intrinsics {
extern "rust-intrinsic" {
+ #[rustc_safe_intrinsic]
pub fn abort() -> !;
+ #[rustc_safe_intrinsic]
pub fn size_of<T>() -> usize;
pub fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
+ #[rustc_safe_intrinsic]
pub fn min_align_of<T>() -> usize;
pub fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize;
pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
pub fn transmute<T, U>(e: T) -> U;
pub fn ctlz_nonzero<T>(x: T) -> T;
+ #[rustc_safe_intrinsic]
pub fn needs_drop<T: ?::Sized>() -> bool;
+ #[rustc_safe_intrinsic]
pub fn bitreverse<T>(x: T) -> T;
+ #[rustc_safe_intrinsic]
pub fn bswap<T>(x: T) -> T;
pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
}
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 e83be3a3d..215d3556a 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -93,6 +93,7 @@ fn start<T: Termination + 'static>(
main: fn() -> T,
argc: isize,
argv: *const *const u8,
+ _sigpipe: u8,
) -> isize {
if argc == 3 {
unsafe { puts(*argv as *const i8); }
diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs
index 0b5b6cd55..ad108c349 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, bench_black_box)]
+#![feature(core_intrinsics, generators, generator_trait, is_sorted)]
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch b/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch
new file mode 100644
index 000000000..0e5e7cdfc
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/patches/0001-abi-cafe-Disable-some-test-on-x86_64-pc-windows-gnu.patch
@@ -0,0 +1,29 @@
+From 2b15fee2bb5fd14e34c7e17e44d99cb34f4c555d Mon Sep 17 00:00:00 2001
+From: Afonso Bordado <afonsobordado@az8.co>
+Date: Tue, 27 Sep 2022 07:55:17 +0100
+Subject: [PATCH] Disable some test on x86_64-pc-windows-gnu
+
+---
+ src/report.rs | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/src/report.rs b/src/report.rs
+index eeec614..f582867 100644
+--- a/src/report.rs
++++ b/src/report.rs
+@@ -48,6 +48,12 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn AbiImpl, callee: &dyn AbiImpl
+ //
+ // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES
+
++ // x86_64-pc-windows-gnu has some broken i128 tests that aren't disabled by default
++ if cfg!(all(target_os = "windows", target_env = "gnu")) && test.test_name == "ui128" {
++ result.run = Link;
++ result.check = Pass(Link);
++ }
++
+ // END OF VENDOR RESERVED AREA
+ //
+ //
+--
+2.30.1.windows.1
+
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-abi-checker-Disable-failing-tests.patch b/compiler/rustc_codegen_cranelift/patches/0001-abi-checker-Disable-failing-tests.patch
deleted file mode 100644
index 526366a75..000000000
--- a/compiler/rustc_codegen_cranelift/patches/0001-abi-checker-Disable-failing-tests.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 1a315ba225577dbbd1f449d9609f16f984f68708 Mon Sep 17 00:00:00 2001
-From: Afonso Bordado <afonso360@users.noreply.github.com>
-Date: Fri, 12 Aug 2022 22:51:58 +0000
-Subject: [PATCH] Disable abi-checker tests
-
----
- src/report.rs | 14 ++++++++++++++
- 1 file changed, 14 insertions(+)
-
-diff --git a/src/report.rs b/src/report.rs
-index 7346f5e..8347762 100644
---- a/src/report.rs
-+++ b/src/report.rs
-@@ -45,6 +45,20 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn AbiImpl, callee: &dyn AbiImpl
- //
- // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES
-
-+ // Currently MSVC has some broken ABI issues. Furthermore, they cause
-+ // a STATUS_ACCESS_VIOLATION, so we can't even run them. Ensure that they compile and link.
-+ if cfg!(windows) && (test.test_name == "bool" || test.test_name == "ui128") {
-+ result.run = Link;
-+ result.check = Pass(Link);
-+ }
-+
-+ // structs is broken in the current release of cranelift for aarch64.
-+ // It has been fixed for cranelift 0.88: https://github.com/bytecodealliance/wasmtime/pull/4634
-+ if cfg!(target_arch = "aarch64") && test.test_name == "structs" {
-+ result.run = Link;
-+ result.check = Pass(Link);
-+ }
-+
- // END OF VENDOR RESERVED AREA
- //
- //
---
-2.34.1
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch
index 54e13b090..89e2b61c1 100644
--- a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch
@@ -1,80 +1,29 @@
-From 97c473937382a5b5858d9cce3c947855d23b2dc5 Mon Sep 17 00:00:00 2001
+From b742f03694b920cc14400727d54424e8e1b60928 Mon Sep 17 00:00:00 2001
From: bjorn3 <bjorn3@users.noreply.github.com>
Date: Thu, 18 Nov 2021 19:28:40 +0100
Subject: [PATCH] Disable unsupported tests
---
- crates/core_simd/src/math.rs | 6 ++++++
- crates/core_simd/src/vector.rs | 2 ++
- crates/core_simd/tests/masks.rs | 2 ++
- crates/core_simd/tests/ops_macros.rs | 4 ++++
- 4 files changed, 14 insertions(+)
+ crates/core_simd/src/elements/int.rs | 8 ++++++++
+ crates/core_simd/src/elements/uint.rs | 4 ++++
+ crates/core_simd/src/masks/full_masks.rs | 6 ++++++
+ crates/core_simd/src/vector.rs | 2 ++
+ crates/core_simd/tests/masks.rs | 3 ---
+ 5 files changed, 20 insertions(+), 3 deletions(-)
-diff --git a/crates/core_simd/src/math.rs b/crates/core_simd/src/math.rs
-index 2bae414..2f87499 100644
---- a/crates/core_simd/src/math.rs
-+++ b/crates/core_simd/src/math.rs
-@@ -5,6 +5,7 @@ macro_rules! impl_uint_arith {
- ($($ty:ty),+) => {
- $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
-
-+ /*
- /// Lanewise saturating add.
- ///
- /// # Examples
-@@ -43,6 +44,7 @@ macro_rules! impl_uint_arith {
- pub fn saturating_sub(self, second: Self) -> Self {
- unsafe { simd_saturating_sub(self, second) }
- }
-+ */
- })+
- }
- }
-@@ -51,6 +53,7 @@ macro_rules! impl_int_arith {
- ($($ty:ty),+) => {
- $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
-
-+ /*
- /// Lanewise saturating add.
- ///
- /// # Examples
-@@ -89,6 +92,7 @@ macro_rules! impl_int_arith {
- pub fn saturating_sub(self, second: Self) -> Self {
- unsafe { simd_saturating_sub(self, second) }
- }
-+ */
-
- /// Lanewise absolute value, implemented in Rust.
- /// Every lane becomes its absolute value.
-@@ -109,6 +113,7 @@ macro_rules! impl_int_arith {
- (self^m) - m
- }
-
-+ /*
- /// Lanewise saturating absolute value, implemented in Rust.
- /// As abs(), except the MIN value becomes MAX instead of itself.
- ///
-@@ -151,6 +156,7 @@ macro_rules! impl_int_arith {
- pub fn saturating_neg(self) -> Self {
- Self::splat(0).saturating_sub(self)
- }
-+ */
- })+
- }
- }
diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs
-index 7c5ec2b..c8631e8 100644
+index e8e8f68..7173c24 100644
--- a/crates/core_simd/src/vector.rs
+++ b/crates/core_simd/src/vector.rs
-@@ -75,6 +75,7 @@ where
- Self(array)
+@@ -250,6 +250,7 @@ where
+ unsafe { intrinsics::simd_cast(self) }
}
+ /*
/// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
/// If an index is out-of-bounds, the lane is instead selected from the `or` vector.
///
-@@ -297,6 +298,7 @@ where
+@@ -473,6 +474,7 @@ where
// Cleared ☢️ *mut T Zone
}
}
@@ -82,26 +31,5 @@ index 7c5ec2b..c8631e8 100644
}
impl<T, const LANES: usize> Copy for Simd<T, LANES>
-diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs
-index 6a8ecd3..68fcb49 100644
---- a/crates/core_simd/tests/masks.rs
-+++ b/crates/core_simd/tests/masks.rs
-@@ -68,6 +68,7 @@ macro_rules! test_mask_api {
- assert_eq!(core_simd::Mask::<$type, 8>::from_int(int), mask);
- }
-
-+ /*
- #[cfg(feature = "generic_const_exprs")]
- #[test]
- fn roundtrip_bitmask_conversion() {
-@@ -80,6 +81,7 @@ macro_rules! test_mask_api {
- assert_eq!(bitmask, [0b01001001, 0b10000011]);
- assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask);
- }
-+ */
- }
- }
- }
--
-2.26.2.7.g19db9cfb68
-
+2.25.1
diff --git a/compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch b/compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch
new file mode 100644
index 000000000..d8775e2d0
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch
@@ -0,0 +1,47 @@
+From eec874c889b8d24e5ad50faded24288150f057b1 Mon Sep 17 00:00:00 2001
+From: Afonso Bordado <afonsobordado@az8.co>
+Date: Tue, 27 Sep 2022 08:13:58 +0100
+Subject: [PATCH] Disable rand tests on mingw
+
+---
+ rand_distr/src/pareto.rs | 2 ++
+ rand_distr/tests/value_stability.rs | 4 ++++
+ 2 files changed, 6 insertions(+)
+
+diff --git a/rand_distr/src/pareto.rs b/rand_distr/src/pareto.rs
+index 217899e..9cedeb7 100644
+--- a/rand_distr/src/pareto.rs
++++ b/rand_distr/src/pareto.rs
+@@ -107,6 +107,8 @@ mod tests {
+ }
+
+ #[test]
++ // This is broken on x86_64-pc-windows-gnu presumably due to a broken powf implementation
++ #[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)]
+ fn value_stability() {
+ fn test_samples<F: Float + core::fmt::Debug, D: Distribution<F>>(
+ distr: D, zero: F, expected: &[F],
+diff --git a/rand_distr/tests/value_stability.rs b/rand_distr/tests/value_stability.rs
+index 192ba74..0101ace 100644
+--- a/rand_distr/tests/value_stability.rs
++++ b/rand_distr/tests/value_stability.rs
+@@ -72,6 +72,8 @@ fn unit_disc_stability() {
+ }
+
+ #[test]
++// This is broken on x86_64-pc-windows-gnu
++#[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)]
+ fn pareto_stability() {
+ test_samples(213, Pareto::new(1.0, 1.0).unwrap(), &[
+ 1.0423688f32, 2.1235929, 4.132709, 1.4679428,
+@@ -143,6 +145,8 @@ fn inverse_gaussian_stability() {
+ }
+
+ #[test]
++// This is broken on x86_64-pc-windows-gnu
++#[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)]
+ fn gamma_stability() {
+ // Gamma has 3 cases: shape == 1, shape < 1, shape > 1
+ test_samples(223, Gamma::new(1.0, 5.0).unwrap(), &[
+--
+2.25.1
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 14f2746ec..c0a2e7a78 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
[toolchain]
-channel = "nightly-2022-08-24"
+channel = "nightly-2022-10-23"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
index 091bfa1e9..d6a377895 100644
--- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
@@ -10,6 +10,8 @@ git fetch
git checkout -- .
git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')"
+git am ../patches/*-sysroot-*.patch
+
git apply - <<EOF
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index d95b5b7f17f..00b6f0e3635 100644
@@ -66,3 +68,7 @@ popd
# FIXME remove once inline asm is fully supported
export RUSTFLAGS="$RUSTFLAGS --cfg=rustix_use_libc"
+
+# Allow the testsuite to use llvm tools
+host_triple=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
+export LLVM_BIN_DIR="$(rustc --print sysroot)/lib/rustlib/$host_triple/bin"
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index 944787612..9b5db3cf8 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -29,10 +29,6 @@ rm src/test/incremental/change_crate_dep_kind.rs
rm src/test/incremental/issue-80691-bad-eval-cache.rs # -Cpanic=abort causes abort instead of exit(101)
# requires compiling with -Cpanic=unwind
-rm src/test/ui/test-attrs/test-fn-signature-verification-for-explicit-return-type.rs # "Cannot run dynamic test fn out-of-process"
-rm src/test/ui/async-await/async-fn-size-moved-locals.rs # -Cpanic=abort shrinks some generator by one byte
-rm src/test/ui/async-await/async-fn-size-uninit-locals.rs # same
-rm src/test/ui/generator/size-moved-locals.rs # same
rm -r src/test/ui/macros/rfc-2011-nicer-assert-messages/
# vendor intrinsics
@@ -67,6 +63,7 @@ rm src/test/ui/target-feature/missing-plusminus.rs # error not implemented
rm src/test/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment
rm -r src/test/run-make/emit-named-files # requires full --emit support
rm src/test/ui/abi/stack-probes.rs # stack probes not yet implemented
+rm src/test/ui/simd/intrinsic/ptr-cast.rs # simd_expose_addr intrinsic unimplemented
# optimization tests
# ==================
@@ -110,12 +107,13 @@ rm src/test/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unorde
# bugs in the test suite
# ======================
rm src/test/ui/backtrace.rs # TODO warning
-rm src/test/ui/empty_global_asm.rs # TODO add needs-asm-support
rm src/test/ui/simple_global_asm.rs # TODO add needs-asm-support
rm src/test/ui/test-attrs/test-type.rs # TODO panic message on stderr. correct stdout
# not sure if this is actually a bug in the test suite, but the symbol list shows the function without leading _ for some reason
rm -r src/test/run-make/native-link-modifier-bundle
+rm src/test/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
+
echo "[TEST] rustc test suite"
RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui,incremental}
popd
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 0497c2570..99059e788 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -465,7 +465,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
let sig = fx.bcx.import_signature(sig);
- (CallTarget::Indirect(sig, method), Some(ptr))
+ (CallTarget::Indirect(sig, method), Some(ptr.get_addr(fx)))
}
// Normal call
@@ -560,7 +560,19 @@ pub(crate) fn codegen_drop<'tcx>(
// we don't actually need to drop anything
} else {
match ty.kind() {
- ty::Dynamic(..) => {
+ ty::Dynamic(_, _, ty::Dyn) => {
+ // IN THIS ARM, WE HAVE:
+ // ty = *mut (dyn Trait)
+ // which is: exists<T> ( *mut T, Vtable<T: Trait> )
+ // args[0] args[1]
+ //
+ // args = ( Data, Vtable )
+ // |
+ // v
+ // /-------\
+ // | ... |
+ // \-------/
+ //
let (ptr, vtable) = drop_place.to_ptr_maybe_unsized();
let ptr = ptr.get_addr(fx);
let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable.unwrap());
@@ -578,6 +590,43 @@ pub(crate) fn codegen_drop<'tcx>(
let sig = fx.bcx.import_signature(sig);
fx.bcx.ins().call_indirect(sig, drop_fn, &[ptr]);
}
+ ty::Dynamic(_, _, ty::DynStar) => {
+ // IN THIS ARM, WE HAVE:
+ // ty = *mut (dyn* Trait)
+ // which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>)
+ //
+ // args = [ * ]
+ // |
+ // v
+ // ( Data, Vtable )
+ // |
+ // v
+ // /-------\
+ // | ... |
+ // \-------/
+ //
+ //
+ // WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING
+ //
+ // data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer)
+ // vtable = (*args[0]).1 // loads the vtable out
+ // (data, vtable) // an equivalent Rust `*mut dyn Trait`
+ //
+ // SO THEN WE CAN USE THE ABOVE CODE.
+ let (data, vtable) = drop_place.to_cvalue(fx).dyn_star_force_data_on_stack(fx);
+ let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable);
+
+ let virtual_drop = Instance {
+ def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0),
+ substs: drop_instance.substs,
+ };
+ let fn_abi =
+ RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty());
+
+ let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
+ let sig = fx.bcx.import_signature(sig);
+ fx.bcx.ins().call_indirect(sig, drop_fn, &[data]);
+ }
_ => {
assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _)));
diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
index 96e25d3a8..e5ad31eb9 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
@@ -193,7 +193,7 @@ pub(super) fn from_casted_value<'tcx>(
kind: StackSlotKind::ExplicitSlot,
// FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
// specify stack slot alignment.
- // Stack slot size may be bigger for for example `[u8; 3]` which is packed into an `i32`.
+ // Stack slot size may be bigger for example `[u8; 3]` which is packed into an `i32`.
// It may also be smaller for example when the type is a wrapper around an integer with a
// larger alignment than the integer.
size: (std::cmp::max(abi_param_size, layout_size) + 15) / 16 * 16,
diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs
index 6d321c7b2..bad8a87b9 100644
--- a/compiler/rustc_codegen_cranelift/src/allocator.rs
+++ b/compiler/rustc_codegen_cranelift/src/allocator.rs
@@ -78,7 +78,7 @@ fn codegen_inner(
let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap();
let mut ctx = Context::new();
- ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig.clone());
+ ctx.func.signature = sig.clone();
{
let mut func_ctx = FunctionBuilderContext::new();
let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
@@ -116,7 +116,7 @@ fn codegen_inner(
let callee_func_id = module.declare_function(callee_name, Linkage::Import, &sig).unwrap();
let mut ctx = Context::new();
- ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig);
+ ctx.func.signature = sig;
{
let mut func_ctx = FunctionBuilderContext::new();
let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs
index fb5313f17..f2e3bf16e 100644
--- a/compiler/rustc_codegen_cranelift/src/archive.rs
+++ b/compiler/rustc_codegen_cranelift/src/archive.rs
@@ -160,6 +160,8 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
let err = err.to_string();
if err == "Unknown file magic" {
// Not an object file; skip it.
+ } else if object::read::archive::ArchiveFile::parse(&*data).is_ok() {
+ // Nested archive file; skip it.
} else {
sess.fatal(&format!(
"error parsing `{}` during archive creation: {}",
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 399474d79..1db445027 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -6,6 +6,8 @@ use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
+use cranelift_codegen::ir::UserFuncName;
+
use crate::constant::ConstantCx;
use crate::debuginfo::FunctionDebugContext;
use crate::prelude::*;
@@ -64,7 +66,7 @@ pub(crate) fn codegen_fn<'tcx>(
let mut func_ctx = FunctionBuilderContext::new();
let mut func = cached_func;
func.clear();
- func.name = ExternalName::user(0, func_id.as_u32());
+ func.name = UserFuncName::user(0, func_id.as_u32());
func.signature = sig;
func.collect_debug_info();
@@ -633,7 +635,12 @@ fn codegen_stmt<'tcx>(
lval.write_cvalue(fx, operand.cast_pointer_to(to_layout));
}
Rvalue::Cast(
- CastKind::Misc
+ CastKind::IntToInt
+ | CastKind::FloatToFloat
+ | CastKind::FloatToInt
+ | CastKind::IntToFloat
+ | CastKind::FnPtrToPtr
+ | CastKind::PtrToPtr
| CastKind::PointerExposeAddress
| CastKind::PointerFromExposedAddress,
ref operand,
@@ -701,9 +708,9 @@ fn codegen_stmt<'tcx>(
let operand = codegen_operand(fx, operand);
operand.unsize_value(fx, lval);
}
- Rvalue::Cast(CastKind::DynStar, _, _) => {
- // FIXME(dyn-star)
- unimplemented!()
+ Rvalue::Cast(CastKind::DynStar, ref operand, _) => {
+ let operand = codegen_operand(fx, operand);
+ operand.coerce_dyn_star(fx, lval);
}
Rvalue::Discriminant(place) => {
let place = codegen_place(fx, place);
@@ -763,11 +770,7 @@ fn codegen_stmt<'tcx>(
lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
}
Rvalue::NullaryOp(null_op, ty) => {
- assert!(
- lval.layout()
- .ty
- .is_sized(fx.tcx.at(stmt.source_info.span), ParamEnv::reveal_all())
- );
+ 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(),
@@ -850,6 +853,7 @@ pub(crate) fn codegen_place<'tcx>(
PlaceElem::Deref => {
cplace = cplace.place_deref(fx);
}
+ PlaceElem::OpaqueCast(ty) => cplace = cplace.place_opaque_cast(fx, ty),
PlaceElem::Field(field, _ty) => {
cplace = cplace.place_field(fx, field);
}
@@ -916,7 +920,7 @@ pub(crate) fn codegen_operand<'tcx>(
let cplace = codegen_place(fx, *place);
cplace.to_cvalue(fx)
}
- Operand::Constant(const_) => crate::constant::codegen_constant(fx, const_),
+ Operand::Constant(const_) => crate::constant::codegen_constant_operand(fx, const_),
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
index dfde97920..f855e20e0 100644
--- a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
+++ b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
@@ -10,6 +10,7 @@ pub(super) struct ConcurrencyLimiter {
helper_thread: Option<HelperThread>,
state: Arc<Mutex<state::ConcurrencyLimiterState>>,
available_token_condvar: Arc<Condvar>,
+ finished: bool,
}
impl ConcurrencyLimiter {
@@ -32,6 +33,7 @@ impl ConcurrencyLimiter {
helper_thread: Some(helper_thread),
state,
available_token_condvar: Arc::new(Condvar::new()),
+ finished: false,
}
}
@@ -56,16 +58,23 @@ impl ConcurrencyLimiter {
let mut state = self.state.lock().unwrap();
state.job_already_done();
}
-}
-impl Drop for ConcurrencyLimiter {
- fn drop(&mut self) {
- //
+ pub(crate) fn finished(mut self) {
self.helper_thread.take();
// Assert that all jobs have finished
let state = Mutex::get_mut(Arc::get_mut(&mut self.state).unwrap()).unwrap();
state.assert_done();
+
+ self.finished = true;
+ }
+}
+
+impl Drop for ConcurrencyLimiter {
+ fn drop(&mut self) {
+ if !self.finished && !std::thread::panicking() {
+ panic!("Forgot to call finished() on ConcurrencyLimiter");
+ }
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 6b4ed9b9d..148b66d95 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -5,10 +5,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::interpret::{
read_target_uint, AllocId, ConstAllocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
};
-use rustc_middle::ty::ConstKind;
-use rustc_span::DUMMY_SP;
-use cranelift_codegen::ir::GlobalValueData;
use cranelift_module::*;
use crate::prelude::*;
@@ -42,15 +39,7 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool {
let mut all_constants_ok = true;
for constant in &fx.mir.required_consts {
let unevaluated = match fx.monomorphize(constant.literal) {
- ConstantKind::Ty(ct) => match ct.kind() {
- ConstKind::Unevaluated(uv) => uv.expand(),
- ConstKind::Value(_) => continue,
- ConstKind::Param(_)
- | ConstKind::Infer(_)
- | ConstKind::Bound(_, _)
- | ConstKind::Placeholder(_)
- | ConstKind::Error(_) => unreachable!("{:?}", ct),
- },
+ ConstantKind::Ty(_) => unreachable!(),
ConstantKind::Unevaluated(uv, _) => uv,
ConstantKind::Val(..) => continue,
};
@@ -90,53 +79,46 @@ pub(crate) fn codegen_tls_ref<'tcx>(
CValue::by_val(tls_ptr, layout)
}
-fn codegen_static_ref<'tcx>(
- fx: &mut FunctionCx<'_, '_, 'tcx>,
- def_id: DefId,
- layout: TyAndLayout<'tcx>,
-) -> CPlace<'tcx> {
- let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
- let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
- if fx.clif_comments.enabled() {
- fx.add_comment(local_data_id, format!("{:?}", def_id));
- }
- let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id);
- assert!(!layout.is_unsized(), "unsized statics aren't supported");
- assert!(
- matches!(
- fx.bcx.func.global_values[local_data_id],
- GlobalValueData::Symbol { tls: false, .. }
- ),
- "tls static referenced without Rvalue::ThreadLocalRef"
- );
- CPlace::for_ptr(crate::pointer::Pointer::new(global_ptr), layout)
-}
-
-pub(crate) fn codegen_constant<'tcx>(
+pub(crate) fn eval_mir_constant<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
constant: &Constant<'tcx>,
-) -> CValue<'tcx> {
- let (const_val, ty) = match fx.monomorphize(constant.literal) {
- ConstantKind::Ty(const_) => unreachable!("{:?}", const_),
- ConstantKind::Unevaluated(ty::Unevaluated { def, substs, promoted }, ty)
+) -> (ConstValue<'tcx>, Ty<'tcx>) {
+ let constant_kind = fx.monomorphize(constant.literal);
+ let uv = match constant_kind {
+ ConstantKind::Ty(const_) => match const_.kind() {
+ ty::ConstKind::Unevaluated(uv) => uv.expand(),
+ ty::ConstKind::Value(val) => {
+ return (fx.tcx.valtree_to_const_val((const_.ty(), val)), const_.ty());
+ }
+ err => span_bug!(
+ constant.span,
+ "encountered bad ConstKind after monomorphizing: {:?}",
+ err
+ ),
+ },
+ ConstantKind::Unevaluated(mir::UnevaluatedConst { def, .. }, _)
if fx.tcx.is_static(def.did) =>
{
- assert!(substs.is_empty());
- assert!(promoted.is_none());
-
- return codegen_static_ref(fx, def.did, fx.layout_of(ty)).to_cvalue(fx);
- }
- ConstantKind::Unevaluated(unevaluated, ty) => {
- match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) {
- Ok(const_val) => (const_val, ty),
- Err(_) => {
- span_bug!(constant.span, "erroneous constant not captured by required_consts");
- }
- }
+ span_bug!(constant.span, "MIR constant refers to static");
}
- ConstantKind::Val(val, ty) => (val, ty),
+ ConstantKind::Unevaluated(uv, _) => uv,
+ ConstantKind::Val(val, _) => return (val, constant_kind.ty()),
};
+ (
+ fx.tcx.const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None).unwrap_or_else(|_err| {
+ span_bug!(constant.span, "erroneous constant not captured by required_consts");
+ }),
+ constant_kind.ty(),
+ )
+}
+
+pub(crate) fn codegen_constant_operand<'tcx>(
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ constant: &Constant<'tcx>,
+) -> CValue<'tcx> {
+ let (const_val, ty) = eval_mir_constant(fx, constant);
+
codegen_const_value(fx, const_val, ty)
}
@@ -253,7 +235,7 @@ pub(crate) fn codegen_const_value<'tcx>(
}
}
-pub(crate) fn pointer_for_allocation<'tcx>(
+fn pointer_for_allocation<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
alloc: ConstAllocation<'tcx>,
) -> crate::pointer::Pointer {
@@ -308,7 +290,7 @@ fn data_id_for_static(
let is_mutable = if tcx.is_mutable_static(def_id) {
true
} else {
- !ty.is_freeze(tcx.at(DUMMY_SP), ParamEnv::reveal_all())
+ !ty.is_freeze(tcx, ParamEnv::reveal_all())
};
let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes();
@@ -476,14 +458,13 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
operand: &Operand<'tcx>,
) -> Option<ConstValue<'tcx>> {
match operand {
- Operand::Constant(const_) => match const_.literal {
- ConstantKind::Ty(const_) => fx
- .monomorphize(const_)
- .eval_for_mir(fx.tcx, ParamEnv::reveal_all())
- .try_to_value(fx.tcx),
+ Operand::Constant(const_) => match fx.monomorphize(const_.literal) {
+ ConstantKind::Ty(const_) => Some(
+ const_.eval_for_mir(fx.tcx, ParamEnv::reveal_all()).try_to_value(fx.tcx).unwrap(),
+ ),
ConstantKind::Val(val, _) => Some(val),
ConstantKind::Unevaluated(uv, _) => {
- fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), uv, None).ok()
+ Some(fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), uv, None).unwrap())
}
},
// FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored
@@ -499,7 +480,16 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
match &stmt.kind {
StatementKind::Assign(local_and_rvalue) if &local_and_rvalue.0 == place => {
match &local_and_rvalue.1 {
- Rvalue::Cast(CastKind::Misc, operand, ty) => {
+ Rvalue::Cast(
+ CastKind::IntToInt
+ | CastKind::FloatToFloat
+ | CastKind::FloatToInt
+ | CastKind::IntToFloat
+ | CastKind::FnPtrToPtr
+ | CastKind::PtrToPtr,
+ operand,
+ ty,
+ ) => {
if computed_const_val.is_some() {
return None; // local assigned twice
}
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 8eabe1cbc..f873561c1 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -106,7 +106,7 @@ impl OngoingCodegen {
}
}
- drop(self.concurrency_limiter);
+ self.concurrency_limiter.finished();
(
CodegenResults {
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index 0e77e4004..6a430b521 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -67,13 +67,12 @@ fn create_jit_module(
hotswap: bool,
) -> (JITModule, CodegenCx) {
let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string());
- let imported_symbols = load_imported_symbols_for_jit(tcx.sess, crate_info);
let isa = crate::build_isa(tcx.sess, backend_config);
let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
jit_builder.hotswap(hotswap);
crate::compiler_builtins::register_functions_for_jit(&mut jit_builder);
- jit_builder.symbols(imported_symbols);
+ jit_builder.symbol_lookup_fn(dep_symbol_lookup_fn(tcx.sess, crate_info));
jit_builder.symbol("__clif_jit_fn", clif_jit_fn as *const u8);
let mut jit_module = JITModule::new(jit_builder);
@@ -286,10 +285,10 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) ->
})
}
-fn load_imported_symbols_for_jit(
+fn dep_symbol_lookup_fn(
sess: &Session,
crate_info: CrateInfo,
-) -> Vec<(String, *const u8)> {
+) -> Box<dyn Fn(&str) -> Option<*const u8>> {
use rustc_middle::middle::dependency_format::Linkage;
let mut dylib_paths = Vec::new();
@@ -316,39 +315,23 @@ fn load_imported_symbols_for_jit(
}
}
- let mut imported_symbols = Vec::new();
- for path in dylib_paths {
- use object::{Object, ObjectSymbol};
- let lib = libloading::Library::new(&path).unwrap();
- let obj = std::fs::read(path).unwrap();
- let obj = object::File::parse(&*obj).unwrap();
- imported_symbols.extend(obj.dynamic_symbols().filter_map(|symbol| {
- let name = symbol.name().unwrap().to_string();
- if name.is_empty() || !symbol.is_global() || symbol.is_undefined() {
- return None;
- }
- if name.starts_with("rust_metadata_") {
- // The metadata is part of a section that is not loaded by the dynamic linker in
- // case of cg_llvm.
- return None;
- }
- let dlsym_name = if cfg!(target_os = "macos") {
- // On macOS `dlsym` expects the name without leading `_`.
- assert!(name.starts_with('_'), "{:?}", name);
- &name[1..]
- } else {
- &name
- };
- let symbol: libloading::Symbol<'_, *const u8> =
- unsafe { lib.get(dlsym_name.as_bytes()) }.unwrap();
- Some((name, *symbol))
- }));
- std::mem::forget(lib)
- }
+ let imported_dylibs = Box::leak(
+ dylib_paths
+ .into_iter()
+ .map(|path| unsafe { libloading::Library::new(&path).unwrap() })
+ .collect::<Box<[_]>>(),
+ );
sess.abort_if_errors();
- imported_symbols
+ Box::new(move |sym_name| {
+ for dylib in &*imported_dylibs {
+ if let Ok(sym) = unsafe { dylib.get::<*const u8>(sym_name.as_bytes()) } {
+ return Some(*sym);
+ }
+ }
+ None
+ })
}
fn codegen_shim<'tcx>(
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index 8b3d475cb..3fcc84d39 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -27,7 +27,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
}
// Used by stdarch
- if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string())
+ if template[0] == InlineAsmTemplatePiece::String("mov ".to_string())
&& matches!(
template[1],
InlineAsmTemplatePiece::Placeholder {
@@ -36,24 +36,26 @@ pub(crate) fn codegen_inline_asm<'tcx>(
span: _
}
)
- && template[2] == InlineAsmTemplatePiece::String("\n".to_string())
- && template[3] == InlineAsmTemplatePiece::String("cpuid".to_string())
- && template[4] == InlineAsmTemplatePiece::String("\n".to_string())
- && template[5] == InlineAsmTemplatePiece::String("xchgq %rbx, ".to_string())
+ && template[2] == InlineAsmTemplatePiece::String(", rbx".to_string())
+ && template[3] == InlineAsmTemplatePiece::String("\n".to_string())
+ && template[4] == InlineAsmTemplatePiece::String("cpuid".to_string())
+ && template[5] == InlineAsmTemplatePiece::String("\n".to_string())
+ && template[6] == InlineAsmTemplatePiece::String("xchg ".to_string())
&& matches!(
- template[6],
+ template[7],
InlineAsmTemplatePiece::Placeholder {
operand_idx: 0,
modifier: Some('r'),
span: _
}
)
+ && template[8] == InlineAsmTemplatePiece::String(", rbx".to_string())
{
assert_eq!(operands.len(), 4);
let (leaf, eax_place) = match operands[1] {
InlineAsmOperand::InOut {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)),
- late: true,
+ late: _,
ref in_value,
out_place: Some(out_place),
} => (
@@ -68,7 +70,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86(
X86InlineAsmRegClass::reg,
)),
- late: true,
+ late: _,
place: Some(place),
} => crate::base::codegen_place(fx, place),
_ => unreachable!(),
@@ -76,7 +78,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
let (sub_leaf, ecx_place) = match operands[2] {
InlineAsmOperand::InOut {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)),
- late: true,
+ late: _,
ref in_value,
out_place: Some(out_place),
} => (
@@ -88,7 +90,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
let edx_place = match operands[3] {
InlineAsmOperand::Out {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)),
- late: true,
+ late: _,
place: Some(place),
} => crate::base::codegen_place(fx, place),
_ => unreachable!(),
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
index a799dca93..783d426c3 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
@@ -14,6 +14,10 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
target: Option<BasicBlock>,
) {
match intrinsic {
+ "llvm.x86.sse2.pause" | "llvm.aarch64.isb" => {
+ // Spin loop hint
+ }
+
// Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
"llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd" => {
intrinsic_args!(fx, args => (a); intrinsic);
@@ -25,8 +29,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
let mut res = fx.bcx.ins().iconst(types::I32, 0);
for lane in (0..lane_count).rev() {
- let a_lane =
- a.value_field(fx, mir::Field::new(lane.try_into().unwrap())).load_scalar(fx);
+ let a_lane = a.value_lane(fx, lane).load_scalar(fx);
// cast float to int
let a_lane = match lane_ty {
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 2e4ca594f..0302b843a 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -84,6 +84,30 @@ fn simd_for_each_lane<'tcx>(
}
}
+fn simd_pair_for_each_lane_typed<'tcx>(
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ x: CValue<'tcx>,
+ y: CValue<'tcx>,
+ ret: CPlace<'tcx>,
+ f: &dyn Fn(&mut FunctionCx<'_, '_, 'tcx>, CValue<'tcx>, CValue<'tcx>) -> CValue<'tcx>,
+) {
+ assert_eq!(x.layout(), y.layout());
+ let layout = x.layout();
+
+ let (lane_count, _lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+ let (ret_lane_count, _ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
+ assert_eq!(lane_count, ret_lane_count);
+
+ for lane_idx in 0..lane_count {
+ let x_lane = x.value_lane(fx, lane_idx);
+ let y_lane = y.value_lane(fx, lane_idx);
+
+ let res_lane = f(fx, x_lane, y_lane);
+
+ ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane);
+ }
+}
+
fn simd_pair_for_each_lane<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
x: CValue<'tcx>,
@@ -504,37 +528,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
_ => unreachable!(),
};
- let signed = type_sign(lhs.layout().ty);
-
- let checked_res = crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs);
-
- let (val, has_overflow) = checked_res.load_scalar_pair(fx);
- let clif_ty = fx.clif_type(lhs.layout().ty).unwrap();
-
- let (min, max) = type_min_max_value(&mut fx.bcx, clif_ty, signed);
-
- let val = match (intrinsic, signed) {
- (sym::saturating_add, false) => fx.bcx.ins().select(has_overflow, max, val),
- (sym::saturating_sub, false) => fx.bcx.ins().select(has_overflow, min, val),
- (sym::saturating_add, true) => {
- let rhs = rhs.load_scalar(fx);
- let rhs_ge_zero =
- fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
- let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min);
- fx.bcx.ins().select(has_overflow, sat_val, val)
- }
- (sym::saturating_sub, true) => {
- let rhs = rhs.load_scalar(fx);
- let rhs_ge_zero =
- fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
- let sat_val = fx.bcx.ins().select(rhs_ge_zero, min, max);
- fx.bcx.ins().select(has_overflow, sat_val, val)
- }
- _ => unreachable!(),
- };
-
- let res = CValue::by_val(val, lhs.layout());
-
+ let res = crate::num::codegen_saturating_int_binop(fx, bin_op, lhs, rhs);
ret.write_cvalue(fx, res);
}
sym::rotate_left => {
@@ -819,8 +813,8 @@ fn codegen_regular_intrinsic_call<'tcx>(
sym::ptr_guaranteed_cmp => {
intrinsic_args!(fx, args => (a, b); intrinsic);
- let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b);
- ret.write_cvalue(fx, val);
+ let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b).load_scalar(fx);
+ ret.write_cvalue(fx, CValue::by_val(val, fx.layout_of(fx.tcx.types.u8)));
}
sym::caller_location => {
@@ -1206,7 +1200,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
// FIXME once unwinding is supported, change this to actually catch panics
let f_sig = fx.bcx.func.import_signature(Signature {
call_conv: fx.target_config.default_call_conv,
- params: vec![AbiParam::new(fx.bcx.func.dfg.value_type(data))],
+ params: vec![AbiParam::new(pointer_ty(fx.tcx))],
returns: vec![],
});
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 1f358b1bb..51fce8c85 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -2,6 +2,7 @@
use rustc_middle::ty::subst::SubstsRef;
use rustc_span::Symbol;
+use rustc_target::abi::Endian;
use super::*;
use crate::prelude::*;
@@ -26,7 +27,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
span: Span,
) {
match intrinsic {
- sym::simd_cast => {
+ sym::simd_as | sym::simd_cast => {
intrinsic_args!(fx, args => (a); intrinsic);
if !a.layout().ty.is_simd() {
@@ -162,6 +163,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
}
}
} else {
+ // FIXME remove this case
intrinsic.as_str()["simd_shuffle".len()..].parse().unwrap()
};
@@ -650,8 +652,128 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
}
}
- // simd_saturating_*
- // simd_bitmask
+ sym::simd_select_bitmask => {
+ intrinsic_args!(fx, args => (m, a, b); intrinsic);
+
+ if !a.layout().ty.is_simd() {
+ report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
+ return;
+ }
+ assert_eq!(a.layout(), b.layout());
+
+ let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
+ let lane_layout = fx.layout_of(lane_ty);
+
+ let m = m.load_scalar(fx);
+
+ for lane in 0..lane_count {
+ let m_lane = fx.bcx.ins().ushr_imm(m, u64::from(lane) as i64);
+ let m_lane = fx.bcx.ins().band_imm(m_lane, 1);
+ let a_lane = a.value_lane(fx, lane).load_scalar(fx);
+ let b_lane = b.value_lane(fx, lane).load_scalar(fx);
+
+ let m_lane = fx.bcx.ins().icmp_imm(IntCC::Equal, m_lane, 0);
+ let res_lane =
+ CValue::by_val(fx.bcx.ins().select(m_lane, b_lane, a_lane), lane_layout);
+
+ ret.place_lane(fx, lane).write_cvalue(fx, res_lane);
+ }
+ }
+
+ sym::simd_bitmask => {
+ intrinsic_args!(fx, args => (a); intrinsic);
+
+ let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
+ let lane_clif_ty = fx.clif_type(lane_ty).unwrap();
+
+ // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a
+ // vector mask and returns the most significant bit (MSB) of each lane in the form
+ // of either:
+ // * an unsigned integer
+ // * an array of `u8`
+ // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits.
+ //
+ // The bit order of the result depends on the byte endianness, LSB-first for little
+ // endian and MSB-first for big endian.
+ let expected_int_bits = lane_count.max(8);
+ let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64);
+
+ match lane_ty.kind() {
+ ty::Int(_) | ty::Uint(_) => {}
+ _ => {
+ fx.tcx.sess.span_fatal(
+ span,
+ &format!(
+ "invalid monomorphization of `simd_bitmask` intrinsic: \
+ vector argument `{}`'s element type `{}`, expected integer element \
+ type",
+ a.layout().ty,
+ lane_ty
+ ),
+ );
+ }
+ }
+
+ let res_type =
+ Type::int_with_byte_size(u16::try_from(expected_bytes).unwrap()).unwrap();
+ let mut res = fx.bcx.ins().iconst(res_type, 0);
+
+ let lanes = match fx.tcx.sess.target.endian {
+ Endian::Big => Box::new(0..lane_count) as Box<dyn Iterator<Item = u64>>,
+ Endian::Little => Box::new((0..lane_count).rev()) as Box<dyn Iterator<Item = u64>>,
+ };
+ for lane in lanes {
+ let a_lane = a.value_lane(fx, lane).load_scalar(fx);
+
+ // extract sign bit of an int
+ let a_lane_sign = fx.bcx.ins().ushr_imm(a_lane, i64::from(lane_clif_ty.bits() - 1));
+
+ // shift sign bit into result
+ let a_lane_sign = clif_intcast(fx, a_lane_sign, res_type, false);
+ res = fx.bcx.ins().ishl_imm(res, 1);
+ res = fx.bcx.ins().bor(res, a_lane_sign);
+ }
+
+ match ret.layout().ty.kind() {
+ ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => {}
+ ty::Array(elem, len)
+ if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
+ && len.try_eval_usize(fx.tcx, ty::ParamEnv::reveal_all())
+ == Some(expected_bytes) => {}
+ _ => {
+ fx.tcx.sess.span_fatal(
+ span,
+ &format!(
+ "invalid monomorphization of `simd_bitmask` intrinsic: \
+ cannot return `{}`, expected `u{}` or `[u8; {}]`",
+ ret.layout().ty,
+ expected_int_bits,
+ expected_bytes
+ ),
+ );
+ }
+ }
+
+ let res = CValue::by_val(res, ret.layout());
+ ret.write_cvalue(fx, res);
+ }
+
+ sym::simd_saturating_add | sym::simd_saturating_sub => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+
+ let bin_op = match intrinsic {
+ sym::simd_saturating_add => BinOp::Add,
+ sym::simd_saturating_sub => BinOp::Sub,
+ _ => unreachable!(),
+ };
+
+ // FIXME use vector instructions when possible
+ simd_pair_for_each_lane_typed(fx, x, y, ret, &|fx, x_lane, y_lane| {
+ crate::num::codegen_saturating_int_binop(fx, bin_op, x_lane, y_lane)
+ });
+ }
+
+ // simd_arith_offset
// simd_scatter
// simd_gather
_ => {
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 913414e76..629d79d50 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -96,8 +96,8 @@ mod prelude {
pub(crate) use cranelift_codegen::ir::function::Function;
pub(crate) use cranelift_codegen::ir::types;
pub(crate) use cranelift_codegen::ir::{
- AbiParam, Block, ExternalName, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc,
- StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value,
+ AbiParam, Block, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc, StackSlot,
+ StackSlotData, StackSlotKind, TrapCode, Type, Value,
};
pub(crate) use cranelift_codegen::isa::{self, CallConv};
pub(crate) use cranelift_codegen::Context;
@@ -251,7 +251,6 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar
let mut flags_builder = settings::builder();
flags_builder.enable("is_pic").unwrap();
- flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
let enable_verifier = if backend_config.enable_verifier { "true" } else { "false" };
flags_builder.set("enable_verifier", enable_verifier).unwrap();
flags_builder.set("regalloc_checker", enable_verifier).unwrap();
@@ -279,6 +278,15 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar
}
}
+ if target_triple.architecture == target_lexicon::Architecture::X86_64 {
+ // Windows depends on stack probes to grow the committed part of the stack
+ flags_builder.enable("enable_probestack").unwrap();
+ flags_builder.set("probestack_strategy", "inline").unwrap();
+ } else {
+ // __cranelift_probestack is not provided and inline stack probes are only supported on x86_64
+ flags_builder.set("enable_probestack", "false").unwrap();
+ }
+
let flags = settings::Flags::new(flags_builder);
let isa_builder = match sess.opts.cg.target_cpu.as_deref() {
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index 3c024a84d..cae6312a6 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(
let main_func_id = m.declare_function(main_name, Linkage::Import, &main_sig).unwrap();
let mut ctx = Context::new();
- ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig);
+ ctx.func.signature = cmain_sig;
{
let mut func_ctx = FunctionBuilderContext::new();
let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs
index 4ce8adb18..ecbab408d 100644
--- a/compiler/rustc_codegen_cranelift/src/num.rs
+++ b/compiler/rustc_codegen_cranelift/src/num.rs
@@ -150,18 +150,12 @@ pub(crate) fn codegen_int_binop<'tcx>(
BinOp::BitXor => b.bxor(lhs, rhs),
BinOp::BitAnd => b.band(lhs, rhs),
BinOp::BitOr => b.bor(lhs, rhs),
- BinOp::Shl => {
- let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
- let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
- fx.bcx.ins().ishl(lhs, actual_shift)
- }
+ BinOp::Shl => b.ishl(lhs, rhs),
BinOp::Shr => {
- let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
- let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
if signed {
- fx.bcx.ins().sshr(lhs, actual_shift)
+ b.sshr(lhs, rhs)
} else {
- fx.bcx.ins().ushr(lhs, actual_shift)
+ b.ushr(lhs, rhs)
}
}
// Compare binops handles by `codegen_binop`.
@@ -279,22 +273,15 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
}
}
BinOp::Shl => {
- let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
- let masked_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
- let val = fx.bcx.ins().ishl(lhs, masked_shift);
+ let val = fx.bcx.ins().ishl(lhs, rhs);
let ty = fx.bcx.func.dfg.value_type(val);
let max_shift = i64::from(ty.bits()) - 1;
let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, rhs, max_shift);
(val, has_overflow)
}
BinOp::Shr => {
- let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
- let masked_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
- let val = if !signed {
- fx.bcx.ins().ushr(lhs, masked_shift)
- } else {
- fx.bcx.ins().sshr(lhs, masked_shift)
- };
+ let val =
+ if !signed { fx.bcx.ins().ushr(lhs, rhs) } else { fx.bcx.ins().sshr(lhs, rhs) };
let ty = fx.bcx.func.dfg.value_type(val);
let max_shift = i64::from(ty.bits()) - 1;
let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, rhs, max_shift);
@@ -309,6 +296,42 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
CValue::by_val_pair(res, has_overflow, out_layout)
}
+pub(crate) fn codegen_saturating_int_binop<'tcx>(
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ bin_op: BinOp,
+ lhs: CValue<'tcx>,
+ rhs: CValue<'tcx>,
+) -> CValue<'tcx> {
+ assert_eq!(lhs.layout().ty, rhs.layout().ty);
+
+ let signed = type_sign(lhs.layout().ty);
+ let clif_ty = fx.clif_type(lhs.layout().ty).unwrap();
+ let (min, max) = type_min_max_value(&mut fx.bcx, clif_ty, signed);
+
+ let checked_res = crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs);
+ let (val, has_overflow) = checked_res.load_scalar_pair(fx);
+
+ let val = match (bin_op, signed) {
+ (BinOp::Add, false) => fx.bcx.ins().select(has_overflow, max, val),
+ (BinOp::Sub, false) => fx.bcx.ins().select(has_overflow, min, val),
+ (BinOp::Add, true) => {
+ let rhs = rhs.load_scalar(fx);
+ let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
+ let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min);
+ fx.bcx.ins().select(has_overflow, sat_val, val)
+ }
+ (BinOp::Sub, true) => {
+ let rhs = rhs.load_scalar(fx);
+ let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
+ let sat_val = fx.bcx.ins().select(rhs_ge_zero, min, max);
+ fx.bcx.ins().select(has_overflow, sat_val, val)
+ }
+ _ => unreachable!(),
+ };
+
+ CValue::by_val(val, lhs.layout())
+}
+
pub(crate) fn codegen_float_binop<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
bin_op: BinOp,
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index dd9d891dd..9c88f7dbc 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -25,7 +25,12 @@ pub(crate) fn unsized_info<'tcx>(
.bcx
.ins()
.iconst(fx.pointer_type, len.eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64),
- (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
+ (
+ &ty::Dynamic(ref data_a, _, src_dyn_kind),
+ &ty::Dynamic(ref data_b, _, target_dyn_kind),
+ ) => {
+ assert_eq!(src_dyn_kind, target_dyn_kind);
+
let old_info =
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
if data_a.principal_def_id() == data_b.principal_def_id() {
@@ -101,6 +106,21 @@ fn unsize_ptr<'tcx>(
}
}
+/// Coerces `src` to `dst_ty` which is guaranteed to be a `dyn*` type.
+pub(crate) fn cast_to_dyn_star<'tcx>(
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ src: Value,
+ src_ty_and_layout: TyAndLayout<'tcx>,
+ dst_ty: Ty<'tcx>,
+ old_info: Option<Value>,
+) -> (Value, Value) {
+ assert!(
+ matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
+ "destination type must be a dyn*"
+ );
+ (src, unsized_info(fx, src_ty_and_layout.ty, dst_ty, old_info))
+}
+
/// Coerce `src`, which is a reference to a value of type `src_ty`,
/// to a value of type `dst_ty` and store the result in `dst`
pub(crate) fn coerce_unsized_into<'tcx>(
@@ -147,6 +167,24 @@ pub(crate) fn coerce_unsized_into<'tcx>(
}
}
+pub(crate) fn coerce_dyn_star<'tcx>(
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ src: CValue<'tcx>,
+ dst: CPlace<'tcx>,
+) {
+ let (data, extra) = if let ty::Dynamic(_, _, ty::DynStar) = src.layout().ty.kind() {
+ let (data, vtable) = src.load_scalar_pair(fx);
+ (data, Some(vtable))
+ } else {
+ let data = src.load_scalar(fx);
+ (data, None)
+ };
+
+ let (data, vtable) = cast_to_dyn_star(fx, data, src.layout(), dst.layout().ty, extra);
+
+ dst.write_cvalue(fx, CValue::by_val_pair(data, vtable, dst.layout()));
+}
+
// Adapted from https://github.com/rust-lang/rust/blob/2a663555ddf36f6b041445894a8c175cd1bc718c/src/librustc_codegen_ssa/glue.rs
pub(crate) fn size_and_align_of_dst<'tcx>(
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index cfaadca94..c3dfbd372 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -107,6 +107,50 @@ impl<'tcx> CValue<'tcx> {
}
}
+ // FIXME remove
+ // Forces the data value of a dyn* value to the stack and returns a pointer to it as well as the
+ // vtable pointer.
+ pub(crate) fn dyn_star_force_data_on_stack(
+ self,
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ ) -> (Value, Value) {
+ assert!(self.1.ty.is_dyn_star());
+
+ match self.0 {
+ CValueInner::ByRef(ptr, None) => {
+ let (a_scalar, b_scalar) = match self.1.abi {
+ Abi::ScalarPair(a, b) => (a, b),
+ _ => unreachable!("dyn_star_force_data_on_stack({:?})", self),
+ };
+ let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
+ let clif_ty2 = scalar_to_clif_type(fx.tcx, b_scalar);
+ let mut flags = MemFlags::new();
+ flags.set_notrap();
+ let vtable = ptr.offset(fx, b_offset).load(fx, clif_ty2, flags);
+ (ptr.get_addr(fx), vtable)
+ }
+ CValueInner::ByValPair(data, vtable) => {
+ 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
+ // specify stack slot alignment.
+ size: (u32::try_from(fx.target_config.pointer_type().bytes()).unwrap() + 15)
+ / 16
+ * 16,
+ });
+ let data_ptr = Pointer::stack_slot(stack_slot);
+ let mut flags = MemFlags::new();
+ flags.set_notrap();
+ data_ptr.store(fx, data, flags);
+
+ (data_ptr.get_addr(fx), vtable)
+ }
+ CValueInner::ByRef(_, Some(_)) | CValueInner::ByVal(_) => {
+ unreachable!("dyn_star_force_data_on_stack({:?})", self)
+ }
+ }
+ }
+
pub(crate) fn try_to_ptr(self) -> Option<(Pointer, Option<Value>)> {
match self.0 {
CValueInner::ByRef(ptr, meta) => Some((ptr, meta)),
@@ -236,6 +280,10 @@ impl<'tcx> CValue<'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>,
@@ -621,6 +669,14 @@ impl<'tcx> CPlace<'tcx> {
}
}
+ pub(crate) fn place_opaque_cast(
+ self,
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ ty: Ty<'tcx>,
+ ) -> CPlace<'tcx> {
+ CPlace { inner: self.inner, layout: fx.layout_of(ty) }
+ }
+
pub(crate) fn place_field(
self,
fx: &mut FunctionCx<'_, '_, 'tcx>,
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs
index 36b3725ef..f04fb82de 100644
--- a/compiler/rustc_codegen_cranelift/src/vtable.rs
+++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -45,12 +45,26 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
arg: CValue<'tcx>,
idx: usize,
-) -> (Value, Value) {
- let (ptr, vtable) = if let Abi::ScalarPair(_, _) = arg.layout().abi {
- arg.load_scalar_pair(fx)
- } else {
- let (ptr, vtable) = arg.try_to_ptr().unwrap();
- (ptr.get_addr(fx), vtable.unwrap())
+) -> (Pointer, Value) {
+ let (ptr, vtable) = 'block: {
+ if let ty::Ref(_, ty, _) = arg.layout().ty.kind() {
+ if ty.is_dyn_star() {
+ let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap().ty);
+ let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout);
+ let ptr = dyn_star.place_field(fx, mir::Field::new(0)).to_ptr();
+ let vtable =
+ dyn_star.place_field(fx, mir::Field::new(1)).to_cvalue(fx).load_scalar(fx);
+ break 'block (ptr, vtable);
+ }
+ }
+
+ if let Abi::ScalarPair(_, _) = arg.layout().abi {
+ let (ptr, vtable) = arg.load_scalar_pair(fx);
+ (Pointer::new(ptr), vtable)
+ } else {
+ let (ptr, vtable) = arg.try_to_ptr().unwrap();
+ (ptr, vtable.unwrap())
+ }
};
let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes();
diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs
index 848c34211..6fb1cbfad 100644
--- a/compiler/rustc_codegen_gcc/src/abi.rs
+++ b/compiler/rustc_codegen_gcc/src/abi.rs
@@ -11,10 +11,6 @@ use crate::intrinsic::ArgAbiExt;
use crate::type_of::LayoutGccExt;
impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
- fn apply_attrs_callsite(&mut self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _callsite: Self::Value) {
- // TODO(antoyo)
- }
-
fn get_param(&mut self, index: usize) -> Self::Value {
let func = self.current_func();
let param = func.get_param(index as i32);
diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs
index 96c773101..f18ae7ea5 100644
--- a/compiler/rustc_codegen_gcc/src/archive.rs
+++ b/compiler/rustc_codegen_gcc/src/archive.rs
@@ -1,6 +1,8 @@
use std::fs::File;
use std::path::{Path, PathBuf};
+use crate::errors::RanlibFailure;
+
use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
use rustc_session::Session;
@@ -182,7 +184,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
std::process::Command::new("ranlib").arg(output).status().expect("Couldn't run ranlib");
if !status.success() {
- self.config.sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
+ self.config.sess.emit_fatal(RanlibFailure::new(status.code()));
}
any_members
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 52fd66af0..c346dbd63 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -12,6 +12,7 @@ use std::borrow::Cow;
use crate::builder::Builder;
use crate::context::CodegenCx;
+use crate::errors::UnwindingInlineAsm;
use crate::type_of::LayoutGccExt;
use crate::callee::get_fn;
@@ -109,7 +110,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], _instance: Instance<'_>, _dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>) {
if options.contains(InlineAsmOptions::MAY_UNWIND) {
self.sess()
- .struct_span_err(span[0], "GCC backend does not support unwinding from inline asm")
+ .create_err(UnwindingInlineAsm { span: span[0] })
.emit();
return;
}
@@ -497,7 +498,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(), builtin_unreachable, &[], None);
+ self.call(self.type_void(), None, builtin_unreachable, &[], None);
}
// Write results to outputs.
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 6994eeb00..a314b7cc2 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -444,11 +444,23 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
self.block.end_with_switch(None, value, default_block, &gcc_cases);
}
- fn invoke(&mut self, typ: Type<'gcc>, 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_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
+ func: RValue<'gcc>,
+ args: &[RValue<'gcc>],
+ then: Block<'gcc>,
+ catch: Block<'gcc>,
+ _funclet: Option<&Funclet>,
+ ) -> RValue<'gcc> {
// TODO(bjorn3): Properly implement unwinding.
- let call_site = self.call(typ, func, args, None);
+ let call_site = self.call(typ, 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 {
+ // TODO(bjorn3): Apply function attributes
+ }
call_site
}
@@ -643,11 +655,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
self.current_func().new_local(None, aligned_type, &format!("stack_var_{}", self.stack_var_count.get())).get_address(None)
}
- fn dynamic_alloca(&mut self, _ty: Type<'gcc>, _align: Align) -> RValue<'gcc> {
- unimplemented!();
- }
-
- fn array_alloca(&mut self, _ty: Type<'gcc>, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> {
+ fn byte_array_alloca(&mut self, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> {
unimplemented!();
}
@@ -1227,16 +1235,27 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
// TODO(antoyo)
}
- fn call(&mut self, _typ: Type<'gcc>, func: RValue<'gcc>, args: &[RValue<'gcc>], funclet: Option<&Funclet>) -> RValue<'gcc> {
+ fn call(
+ &mut self,
+ _typ: Type<'gcc>,
+ fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
+ func: RValue<'gcc>,
+ args: &[RValue<'gcc>],
+ funclet: Option<&Funclet>,
+ ) -> RValue<'gcc> {
// FIXME(antoyo): remove when having a proper API.
let gcc_func = unsafe { std::mem::transmute(func) };
- if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() {
+ let call = if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() {
self.function_call(func, args, funclet)
}
else {
// If it's a not function that was defined, it's a function pointer.
self.function_ptr_call(func, args, funclet)
+ };
+ if let Some(_fn_abi) = fn_abi {
+ // TODO(bjorn3): Apply function attributes
}
+ call
}
fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs
index 356c03ee3..81f533288 100644
--- a/compiler/rustc_codegen_gcc/src/consts.rs
+++ b/compiler/rustc_codegen_gcc/src/consts.rs
@@ -14,6 +14,7 @@ use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRan
use crate::base;
use crate::context::CodegenCx;
+use crate::errors::LinkageConstOrMutType;
use crate::type_of::LayoutGccExt;
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
@@ -368,10 +369,7 @@ fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &Codeg
cx.layout_of(mt.ty).gcc_type(cx, true)
}
else {
- cx.sess().span_fatal(
- span,
- "must have type `*const T` or `*mut T` due to `#[linkage]` attribute",
- )
+ cx.sess().emit_fatal(LinkageConstOrMutType { span: span })
};
// Declare a symbol `foo` with the desired linkage.
let global1 = cx.declare_global_with_linkage(&sym, llty2, base::global_linkage_to_gcc(linkage));
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 478f6d893..62a61eb85 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -13,7 +13,7 @@ use rustc_middle::mir::mono::CodegenUnit;
use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers};
use rustc_session::Session;
-use rustc_span::Span;
+use rustc_span::{Span, source_map::respan};
use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
use rustc_target::spec::{HasTargetSpec, Target, TlsModel};
@@ -293,7 +293,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
self.is_native_int_type(typ) || self.is_non_native_int_type(typ) || typ.is_compatible_with(self.bool_type)
}
- pub fn sess(&self) -> &Session {
+ pub fn sess(&self) -> &'tcx Session {
&self.tcx.sess
}
@@ -416,10 +416,6 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
self.codegen_unit
}
- fn used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
- unimplemented!();
- }
-
fn set_frame_pointer_type(&self, _llfn: RValue<'gcc>) {
// TODO(antoyo)
}
@@ -428,10 +424,6 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
// TODO(antoyo)
}
- fn create_used_variable(&self) {
- unimplemented!();
- }
-
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
if self.get_declared_value("main").is_none() {
Some(self.declare_cfn("main", fn_type))
@@ -443,14 +435,6 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
None
}
}
-
- fn compiler_used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
- unimplemented!()
- }
-
- fn create_compiler_used_variable(&self) {
- unimplemented!()
- }
}
impl<'gcc, 'tcx> HasTyCtxt<'tcx> for CodegenCx<'gcc, 'tcx> {
@@ -477,7 +461,7 @@ impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
#[inline]
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
if let LayoutError::SizeOverflow(_) = err {
- self.sess().span_fatal(span, &err.to_string())
+ self.sess().emit_fatal(respan(span, err))
} else {
span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
}
@@ -495,7 +479,7 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
fn_abi_request: FnAbiRequest<'tcx>,
) -> ! {
if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
- self.sess().span_fatal(span, &err.to_string())
+ self.sess().emit_fatal(respan(span, err))
} else {
match fn_abi_request {
FnAbiRequest::OfFnPtr { sig, extra_args } => {
diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs
new file mode 100644
index 000000000..15ad90f90
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/errors.rs
@@ -0,0 +1,242 @@
+use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
+use rustc_macros::Diagnostic;
+use rustc_middle::ty::Ty;
+use rustc_span::{Span, Symbol};
+use std::borrow::Cow;
+
+struct ExitCode(Option<i32>);
+
+impl IntoDiagnosticArg for ExitCode {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ let ExitCode(exit_code) = self;
+ match exit_code {
+ Some(t) => t.into_diagnostic_arg(),
+ None => DiagnosticArgValue::Str(Cow::Borrowed("<signal>")),
+ }
+ }
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_ranlib_failure)]
+pub(crate) struct RanlibFailure {
+ exit_code: ExitCode,
+}
+
+impl RanlibFailure {
+ pub fn new(exit_code: Option<i32>) -> Self {
+ RanlibFailure { exit_code: ExitCode(exit_code) }
+ }
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_basic_integer, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationBasicInteger<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_invalid_float_vector, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationInvalidFloatVector<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub elem_ty: &'a str,
+ pub vec_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_not_float, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationNotFloat<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_unrecognized, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationUnrecognized {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_expected_signed_unsigned, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationExpectedSignedUnsigned<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub elem_ty: Ty<'a>,
+ pub vec_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_unsupported_element, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationUnsupportedElement<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub in_ty: Ty<'a>,
+ pub elem_ty: Ty<'a>,
+ pub ret_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_invalid_bitmask, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationInvalidBitmask<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub ty: Ty<'a>,
+ pub expected_int_bits: u64,
+ pub expected_bytes: u64,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_simd_shuffle, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationSimdShuffle<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_expected_simd, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationExpectedSimd<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub position: &'a str,
+ pub found_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_mask_type, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationMaskType<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_return_length, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationReturnLength<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub in_len: u64,
+ pub ret_ty: Ty<'a>,
+ pub out_len: u64,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_return_length_input_type, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationReturnLengthInputType<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub in_len: u64,
+ pub in_ty: Ty<'a>,
+ pub ret_ty: Ty<'a>,
+ pub out_len: u64,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_return_element, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationReturnElement<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub in_elem: Ty<'a>,
+ pub in_ty: Ty<'a>,
+ pub ret_ty: Ty<'a>,
+ pub out_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_return_type, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationReturnType<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub in_elem: Ty<'a>,
+ pub in_ty: Ty<'a>,
+ pub ret_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_inserted_type, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationInsertedType<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub in_elem: Ty<'a>,
+ pub in_ty: Ty<'a>,
+ pub out_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_return_integer_type, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationReturnIntegerType<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub ret_ty: Ty<'a>,
+ pub out_ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_mismatched_lengths, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationMismatchedLengths {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub m_len: u64,
+ pub v_len: u64,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_unsupported_cast, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationUnsupportedCast<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub in_ty: Ty<'a>,
+ pub in_elem: Ty<'a>,
+ pub ret_ty: Ty<'a>,
+ pub out_elem: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_invalid_monomorphization_unsupported_operation, code = "E0511")]
+pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub in_ty: Ty<'a>,
+ pub in_elem: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_linkage_const_or_mut_type)]
+pub(crate) struct LinkageConstOrMutType {
+ #[primary_span]
+ pub span: Span
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_lto_not_supported)]
+pub(crate) struct LTONotSupported;
+
+#[derive(Diagnostic)]
+#[diag(codegen_gcc_unwinding_inline_asm)]
+pub(crate) struct UnwindingInlineAsm {
+ #[primary_span]
+ pub span: Span
+}
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 02cedd464..49be6c649 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -4,7 +4,7 @@ mod simd;
use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp, FunctionType};
use rustc_codegen_ssa::MemFlags;
use rustc_codegen_ssa::base::wants_msvc_seh;
-use rustc_codegen_ssa::common::{IntPredicate, span_invalid_monomorphization_error};
+use rustc_codegen_ssa::common::IntPredicate;
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods};
@@ -20,6 +20,7 @@ use crate::abi::GccType;
use crate::builder::Builder;
use crate::common::{SignType, TypeReflection};
use crate::context::CodegenCx;
+use crate::errors::InvalidMonomorphizationBasicInteger;
use crate::type_of::LayoutGccExt;
use crate::intrinsic::simd::generic_simd_intrinsic;
@@ -99,7 +100,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(), func, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None)
+ self.call(self.type_void(), None, func, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None)
},
sym::likely => {
self.expect(args[0].immediate(), true)
@@ -242,15 +243,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
_ => bug!(),
},
None => {
- span_invalid_monomorphization_error(
- tcx.sess,
- span,
- &format!(
- "invalid monomorphization of `{}` intrinsic: \
- expected basic integer type, found `{}`",
- name, ty
- ),
- );
+ tcx.sess.emit_err(InvalidMonomorphizationBasicInteger { span, name, ty });
return;
}
}
@@ -348,7 +341,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(), func, &[], None);
+ self.call(self.type_void(), None, func, &[], None);
}
fn assume(&mut self, value: Self::Value) {
@@ -1131,7 +1124,7 @@ fn try_intrinsic<'gcc, 'tcx>(bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue<
// NOTE: the `|| true` here is to use the panic=abort strategy with panic=unwind too
if bx.sess().panic_strategy() == PanicStrategy::Abort || true {
// TODO(bjorn3): Properly implement unwinding and remove the `|| true` once this is done.
- bx.call(bx.type_void(), try_func, &[data], None);
+ bx.call(bx.type_void(), 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;
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
index 2401f3350..12e416f62 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
@@ -2,7 +2,7 @@ use std::cmp::Ordering;
use gccjit::{BinaryOp, RValue, Type, ToRValue};
use rustc_codegen_ssa::base::compare_simd_types;
-use rustc_codegen_ssa::common::{TypeKind, span_invalid_monomorphization_error};
+use rustc_codegen_ssa::common::TypeKind;
use rustc_codegen_ssa::mir::operand::OperandRef;
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods};
@@ -14,43 +14,48 @@ use rustc_span::{Span, Symbol, sym};
use rustc_target::abi::Align;
use crate::builder::Builder;
+use crate::errors::{
+ InvalidMonomorphizationInvalidFloatVector,
+ InvalidMonomorphizationNotFloat,
+ InvalidMonomorphizationUnrecognized,
+ InvalidMonomorphizationExpectedSignedUnsigned,
+ InvalidMonomorphizationUnsupportedElement,
+ InvalidMonomorphizationInvalidBitmask,
+ InvalidMonomorphizationSimdShuffle,
+ InvalidMonomorphizationExpectedSimd,
+ InvalidMonomorphizationMaskType,
+ InvalidMonomorphizationReturnLength,
+ InvalidMonomorphizationReturnLengthInputType,
+ InvalidMonomorphizationReturnElement,
+ InvalidMonomorphizationReturnType,
+ InvalidMonomorphizationInsertedType,
+ InvalidMonomorphizationReturnIntegerType,
+ InvalidMonomorphizationMismatchedLengths,
+ InvalidMonomorphizationUnsupportedCast,
+ InvalidMonomorphizationUnsupportedOperation
+};
use crate::intrinsic;
pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, name: Symbol, callee_ty: Ty<'tcx>, args: &[OperandRef<'tcx, RValue<'gcc>>], ret_ty: Ty<'tcx>, llret_ty: Type<'gcc>, span: Span) -> Result<RValue<'gcc>, ()> {
// macros for error handling:
- #[allow(unused_macro_rules)]
- macro_rules! emit_error {
- ($msg: tt) => {
- emit_error!($msg, )
- };
- ($msg: tt, $($fmt: tt)*) => {
- span_invalid_monomorphization_error(
- bx.sess(), span,
- &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
- name, $($fmt)*));
- }
- }
-
macro_rules! return_error {
- ($($fmt: tt)*) => {
+ ($err:expr) => {
{
- emit_error!($($fmt)*);
+ bx.sess().emit_err($err);
return Err(());
}
}
}
-
macro_rules! require {
- ($cond: expr, $($fmt: tt)*) => {
+ ($cond:expr, $err:expr) => {
if !$cond {
- return_error!($($fmt)*);
+ return_error!($err);
}
- };
+ }
}
-
macro_rules! require_simd {
($ty: expr, $position: expr) => {
- require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty)
+ require!($ty.is_simd(), InvalidMonomorphizationExpectedSimd { span, name, position: $position, found_ty: $ty })
};
}
@@ -82,10 +87,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
bx.load(int_ty, ptr, Align::ONE)
}
_ => return_error!(
- "invalid bitmask `{}`, expected `u{}` or `[u8; {}]`",
- mask_ty,
- expected_int_bits,
- expected_bytes
+ InvalidMonomorphizationInvalidBitmask { span, name, ty: mask_ty, expected_int_bits, expected_bytes }
),
};
@@ -127,18 +129,11 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
require!(
in_len == out_len,
- "expected return type with length {} (same as input type `{}`), \
- found `{}` with length {}",
- in_len,
- in_ty,
- ret_ty,
- out_len
+ InvalidMonomorphizationReturnLengthInputType { span, name, in_len, in_ty, ret_ty, out_len }
);
require!(
bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
- "expected return type with integer elements, found `{}` with non-integer `{}`",
- ret_ty,
- out_ty
+ InvalidMonomorphizationReturnIntegerType {span, name, ret_ty, out_ty}
);
return Ok(compare_simd_types(
@@ -163,8 +158,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
})
}
_ => return_error!(
- "simd_shuffle index must be an array of `u32`, got `{}`",
- args[2].layout.ty
+ InvalidMonomorphizationSimdShuffle { span, name, ty: args[2].layout.ty }
),
}
}
@@ -179,19 +173,11 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
require!(
out_len == n,
- "expected return type of length {}, found `{}` with length {}",
- n,
- ret_ty,
- out_len
+ InvalidMonomorphizationReturnLength { span, name, in_len: n, ret_ty, out_len }
);
require!(
in_elem == out_ty,
- "expected return element type `{}` (element of input `{}`), \
- found `{}` with element type `{}`",
- in_elem,
- in_ty,
- ret_ty,
- out_ty
+ InvalidMonomorphizationReturnElement { span, name, in_elem, in_ty, ret_ty, out_ty }
);
let vector = args[2].immediate();
@@ -207,10 +193,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
if name == sym::simd_insert {
require!(
in_elem == arg_tys[2],
- "expected inserted type `{}` (element of input `{}`), found `{}`",
- in_elem,
- in_ty,
- arg_tys[2]
+ InvalidMonomorphizationInsertedType { span, name, in_elem, in_ty, out_ty: arg_tys[2] }
);
let vector = args[0].immediate();
let index = args[1].immediate();
@@ -263,10 +246,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
if name == sym::simd_extract {
require!(
ret_ty == in_elem,
- "expected return type `{}` (element of input `{}`), found `{}`",
- in_elem,
- in_ty,
- ret_ty
+ InvalidMonomorphizationReturnType { span, name, in_elem, in_ty, ret_ty }
);
let vector = args[0].immediate();
return Ok(bx.context.new_vector_access(None, vector, args[1].immediate()).to_rvalue());
@@ -279,13 +259,11 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
require!(
m_len == v_len,
- "mismatched lengths: mask length `{}` != other vector length `{}`",
- m_len,
- v_len
+ InvalidMonomorphizationMismatchedLengths { span, name, m_len, v_len }
);
match m_elem_ty.kind() {
ty::Int(_) => {}
- _ => return_error!("mask element type is `{}`, expected `i_`", m_elem_ty),
+ _ => return_error!(InvalidMonomorphizationMaskType { span, name, ty: m_elem_ty }),
}
return Ok(bx.vector_select(args[0].immediate(), args[1].immediate(), args[2].immediate()));
}
@@ -295,12 +273,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
require!(
in_len == out_len,
- "expected return type with length {} (same as input type `{}`), \
- found `{}` with length {}",
- in_len,
- in_ty,
- ret_ty,
- out_len
+ InvalidMonomorphizationReturnLengthInputType { span, name, in_len, in_ty, ret_ty, out_len }
);
// casting cares about nominal type, not just structural type
if in_elem == out_elem {
@@ -412,13 +385,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
}
_ => { /* Unsupported. Fallthrough. */ }
}
- require!(
- false,
- "unsupported cast from `{}` with element `{}` to `{}` with element `{}`",
- in_ty,
- in_elem,
- ret_ty,
- out_elem
+ return_error!(
+ InvalidMonomorphizationUnsupportedCast { span, name, in_ty, in_elem, ret_ty, out_elem }
);
}
@@ -431,10 +399,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
})*
_ => {},
}
- require!(false,
- "unsupported operation on `{}` with element `{}`",
- in_ty,
- in_elem)
+ return_error!(InvalidMonomorphizationUnsupportedOperation { span, name, in_ty, in_elem })
})*
}
}
@@ -448,23 +413,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
span: Span,
args: &[OperandRef<'tcx, RValue<'gcc>>],
) -> Result<RValue<'gcc>, ()> {
- macro_rules! emit_error {
- ($msg: tt, $($fmt: tt)*) => {
- span_invalid_monomorphization_error(
- bx.sess(), span,
- &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
- name, $($fmt)*));
- }
- }
macro_rules! return_error {
- ($($fmt: tt)*) => {
+ ($err:expr) => {
{
- emit_error!($($fmt)*);
+ bx.sess().emit_err($err);
return Err(());
}
}
}
-
let (elem_ty_str, elem_ty) =
if let ty::Float(f) = in_elem.kind() {
let elem_ty = bx.cx.type_float_from_ty(*f);
@@ -472,16 +428,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
32 => ("f32", elem_ty),
64 => ("f64", elem_ty),
_ => {
- return_error!(
- "unsupported element type `{}` of floating-point vector `{}`",
- f.name_str(),
- in_ty
- );
+ return_error!(InvalidMonomorphizationInvalidFloatVector { span, name, elem_ty: f.name_str(), vec_ty: in_ty });
}
}
}
else {
- return_error!("`{}` is not a floating-point type", in_ty);
+ return_error!(InvalidMonomorphizationNotFloat { span, name, ty: in_ty });
};
let vec_ty = bx.cx.type_vector(elem_ty, in_len);
@@ -504,12 +456,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)),
sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)),
sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)),
- _ => return_error!("unrecognized intrinsic `{}`", name),
+ _ => return_error!(InvalidMonomorphizationUnrecognized { span, name })
};
let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str);
let function = intrinsic::llvm::intrinsic(llvm_name, &bx.cx);
let function: RValue<'gcc> = unsafe { std::mem::transmute(function) };
- let c = bx.call(fn_ty, function, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None);
+ let c = bx.call(fn_ty, None, function, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None);
Ok(c)
}
@@ -557,10 +509,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
})*
_ => {},
}
- require!(false,
- "unsupported operation on `{}` with element `{}`",
- in_ty,
- in_elem)
+ return_error!(InvalidMonomorphizationUnsupportedOperation { span, name, in_ty, in_elem })
})*
}
}
@@ -579,12 +528,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)),
ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_uint_from_ty(i)),
_ => {
- return_error!(
- "expected element type `{}` of vector type `{}` \
- to be a signed or unsigned integer type",
- arg_tys[0].simd_size_and_type(bx.tcx()).1,
- arg_tys[0]
- );
+ return_error!(InvalidMonomorphizationExpectedSignedUnsigned {
+ span,
+ name,
+ elem_ty: arg_tys[0].simd_size_and_type(bx.tcx()).1,
+ vec_ty: arg_tys[0],
+ });
}
};
let builtin_name =
@@ -617,10 +566,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
if name == sym::$name {
require!(
ret_ty == in_elem,
- "expected return type `{}` (element of input `{}`), found `{}`",
- in_elem,
- in_ty,
- ret_ty
+ InvalidMonomorphizationReturnType { span, name, in_elem, in_ty, ret_ty }
);
return match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => {
@@ -644,13 +590,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
Ok(bx.vector_reduce_op(args[0].immediate(), $vec_op))
}
}
- _ => return_error!(
- "unsupported {} from `{}` with element `{}` to `{}`",
- sym::$name,
- in_ty,
- in_elem,
- ret_ty
- ),
+ _ => return_error!(InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }),
};
}
};
@@ -676,20 +616,11 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
if name == sym::$name {
require!(
ret_ty == in_elem,
- "expected return type `{}` (element of input `{}`), found `{}`",
- in_elem,
- in_ty,
- ret_ty
+ InvalidMonomorphizationReturnType { span, name, in_elem, in_ty, ret_ty }
);
return match in_elem.kind() {
ty::Int(_) | ty::Uint(_) | ty::Float(_) => Ok(bx.$reduction(args[0].immediate())),
- _ => return_error!(
- "unsupported {} from `{}` with element `{}` to `{}`",
- sym::$name,
- in_ty,
- in_elem,
- ret_ty
- ),
+ _ => return_error!(InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }),
};
}
};
@@ -704,22 +635,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
let input = if !$boolean {
require!(
ret_ty == in_elem,
- "expected return type `{}` (element of input `{}`), found `{}`",
- in_elem,
- in_ty,
- ret_ty
+ InvalidMonomorphizationReturnType { span, name, in_elem, in_ty, ret_ty }
);
args[0].immediate()
} else {
match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => {}
- _ => return_error!(
- "unsupported {} from `{}` with element `{}` to `{}`",
- sym::$name,
- in_ty,
- in_elem,
- ret_ty
- ),
+ _ => return_error!(InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }),
}
// boolean reductions operate on vectors of i1s:
@@ -733,11 +655,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
Ok(if !$boolean { r } else { bx.zext(r, bx.type_bool()) })
}
_ => return_error!(
- "unsupported {} from `{}` with element `{}` to `{}`",
- sym::$name,
- in_ty,
- in_elem,
- ret_ty
+ InvalidMonomorphizationUnsupportedElement { span, name, in_ty, elem_ty: in_elem, ret_ty }
),
};
}
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 223466fb9..accd02ab0 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -18,6 +18,8 @@
#![recursion_limit="256"]
#![warn(rust_2018_idioms)]
#![warn(unused_lifetimes)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
extern crate rustc_apfloat;
extern crate rustc_ast;
@@ -25,6 +27,7 @@ extern crate rustc_codegen_ssa;
extern crate rustc_data_structures;
extern crate rustc_errors;
extern crate rustc_hir;
+extern crate rustc_macros;
extern crate rustc_metadata;
extern crate rustc_middle;
extern crate rustc_session;
@@ -50,6 +53,7 @@ mod context;
mod coverageinfo;
mod debuginfo;
mod declare;
+mod errors;
mod int;
mod intrinsic;
mod mono_item;
@@ -59,6 +63,7 @@ mod type_of;
use std::any::Any;
use std::sync::{Arc, Mutex};
+use crate::errors::LTONotSupported;
use gccjit::{Context, OptimizationLevel, CType};
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
@@ -97,7 +102,7 @@ pub struct GccCodegenBackend {
impl CodegenBackend for GccCodegenBackend {
fn init(&self, sess: &Session) {
if sess.lto() != Lto::No {
- sess.warn("LTO is not supported. You may get a linker error.");
+ sess.emit_warning(LTONotSupported {});
}
let temp_dir = TempDir::new().expect("cannot create temporary directory");
@@ -166,15 +171,6 @@ impl ExtraBackendMethods for GccCodegenBackend {
Ok(())
})
}
-
- fn target_cpu<'b>(&self, _sess: &'b Session) -> &'b str {
- unimplemented!();
- }
-
- fn tune_cpu<'b>(&self, _sess: &'b Session) -> Option<&'b str> {
- None
- // TODO(antoyo)
- }
}
pub struct ModuleBuffer;
@@ -205,7 +201,6 @@ impl WriteBackendMethods for GccCodegenBackend {
type Module = GccContext;
type TargetMachine = ();
type ModuleBuffer = ModuleBuffer;
- type Context = ();
type ThinData = ();
type ThinBuffer = ThinBuffer;
diff --git a/compiler/rustc_codegen_gcc/tests/run/asm.rs b/compiler/rustc_codegen_gcc/tests/run/asm.rs
index 46abbb553..38c1eac7a 100644
--- a/compiler/rustc_codegen_gcc/tests/run/asm.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/asm.rs
@@ -3,11 +3,12 @@
// Run-time:
// status: 0
-#![feature(asm_const, asm_sym)]
+#![feature(asm_const)]
use std::arch::{asm, global_asm};
-global_asm!("
+global_asm!(
+ "
.global add_asm
add_asm:
mov rax, rdi
@@ -132,7 +133,9 @@ fn main() {
assert_eq!(x, 43);
// check sym fn
- extern "C" fn foo() -> u64 { 42 }
+ extern "C" fn foo() -> u64 {
+ 42
+ }
let x: u64;
unsafe {
asm!("call {}", sym foo, lateout("rax") x);
diff --git a/compiler/rustc_codegen_gcc/tests/run/int.rs b/compiler/rustc_codegen_gcc/tests/run/int.rs
index 2b90e4ae8..75779622b 100644
--- a/compiler/rustc_codegen_gcc/tests/run/int.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/int.rs
@@ -3,7 +3,7 @@
// Run-time:
// status: 0
-#![feature(bench_black_box, const_black_box, core_intrinsics, start)]
+#![feature(const_black_box, core_intrinsics, start)]
#![no_std]
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index 74115353a..0ad39c240 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -5,13 +5,11 @@ edition = "2021"
[lib]
test = false
-doctest = false
[dependencies]
bitflags = "1.0"
cstr = "0.2"
libc = "0.2"
-libloading = "0.7.1"
measureme = "10.0.0"
object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "archive", "coff", "elf", "macho", "pe"] }
tracing = "0.1"
@@ -35,3 +33,4 @@ 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"
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 26f5225f6..d478efc86 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -592,10 +592,6 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
}
impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
- fn apply_attrs_callsite(&mut self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, callsite: Self::Value) {
- fn_abi.apply_attrs_callsite(self, callsite)
- }
-
fn get_param(&mut self, index: usize) -> Self::Value {
llvm::get_param(self.llfn(), index as c_uint)
}
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 5202ac697..017513721 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -430,9 +430,9 @@ pub(crate) fn inline_asm_call<'ll>(
);
let call = if let Some((dest, catch, funclet)) = dest_catch_funclet {
- bx.invoke(fty, v, inputs, dest, catch, funclet)
+ bx.invoke(fty, None, v, inputs, dest, catch, funclet)
} else {
- bx.call(fty, v, inputs, None)
+ bx.call(fty, None, v, inputs, None)
};
// Store mark in a metadata node so we can map LLVM errors
@@ -551,6 +551,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
format!("{{{}}}", reg.name())
}
}
+ // The constraints can be retrieved from
+ // https://llvm.org/docs/LangRef.html#supported-constraint-code-list
InlineAsmRegOrRegClass::RegClass(reg) => match reg {
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r",
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w",
@@ -624,6 +626,8 @@ fn modifier_to_llvm(
reg: InlineAsmRegClass,
modifier: Option<char>,
) -> Option<char> {
+ // The modifiers can be retrieved from
+ // https://llvm.org/docs/LangRef.html#asm-template-argument-modifiers
match reg {
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => modifier,
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg)
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index ed96355a0..082665bba 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -2,16 +2,20 @@
use std::env;
use std::ffi::{CStr, CString, OsString};
-use std::io;
+use std::fs;
+use std::io::{self, Write};
use std::mem;
use std::path::{Path, PathBuf};
use std::ptr;
use std::str;
+use object::read::macho::FatArch;
+
use crate::common;
use crate::llvm::archive_ro::{ArchiveRO, Child};
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
+use rustc_data_structures::memmap::Mmap;
use rustc_session::cstore::DllImport;
use rustc_session::Session;
@@ -53,13 +57,70 @@ fn llvm_machine_type(cpu: &str) -> LLVMMachineType {
}
}
+fn try_filter_fat_archs(
+ archs: object::read::Result<&[impl FatArch]>,
+ target_arch: object::Architecture,
+ archive_path: &Path,
+ archive_map_data: &[u8],
+) -> io::Result<Option<PathBuf>> {
+ let archs = archs.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
+
+ let desired = match archs.iter().filter(|a| a.architecture() == target_arch).next() {
+ Some(a) => a,
+ None => return Ok(None),
+ };
+
+ let (mut new_f, extracted_path) = tempfile::Builder::new()
+ .suffix(archive_path.file_name().unwrap())
+ .tempfile()?
+ .keep()
+ .unwrap();
+
+ new_f.write_all(
+ desired.data(archive_map_data).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?,
+ )?;
+
+ Ok(Some(extracted_path))
+}
+
+fn try_extract_macho_fat_archive(
+ sess: &Session,
+ archive_path: &Path,
+) -> io::Result<Option<PathBuf>> {
+ let archive_map = unsafe { Mmap::map(fs::File::open(&archive_path)?)? };
+ let target_arch = match sess.target.arch.as_ref() {
+ "aarch64" => object::Architecture::Aarch64,
+ "x86_64" => object::Architecture::X86_64,
+ _ => return Ok(None),
+ };
+
+ match object::macho::FatHeader::parse(&*archive_map) {
+ Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC => {
+ let archs = object::macho::FatHeader::parse_arch32(&*archive_map);
+ try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
+ }
+ Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC_64 => {
+ let archs = object::macho::FatHeader::parse_arch64(&*archive_map);
+ try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map)
+ }
+ // Not a FatHeader at all, just return None.
+ _ => Ok(None),
+ }
+}
+
impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
fn add_archive(
&mut self,
archive: &Path,
skip: Box<dyn FnMut(&str) -> bool + 'static>,
) -> io::Result<()> {
- let archive_ro = match ArchiveRO::open(archive) {
+ let mut archive = archive.to_path_buf();
+ if self.sess.target.llvm_target.contains("-apple-macosx") {
+ if let Some(new_archive) = try_extract_macho_fat_archive(&self.sess, &archive)? {
+ archive = new_archive
+ }
+ }
+ let archive_ro = match ArchiveRO::open(&archive) {
Ok(ar) => ar,
Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
};
@@ -67,7 +128,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
return Ok(());
}
self.additions.push(Addition::Archive {
- path: archive.to_path_buf(),
+ path: archive,
archive: archive_ro,
skip: Box::new(skip),
});
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index a89df00e2..a49cc7f8d 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -1,8 +1,6 @@
-use crate::back::write::{
- self, save_temp_bitcode, to_llvm_opt_settings, with_llvm_pmb, DiagnosticHandlers,
-};
-use crate::llvm::{self, build_string, False, True};
-use crate::{llvm_util, LlvmCodegenBackend, ModuleLlvm};
+use crate::back::write::{self, save_temp_bitcode, DiagnosticHandlers};
+use crate::llvm::{self, build_string};
+use crate::{LlvmCodegenBackend, ModuleLlvm};
use object::read::archive::ArchiveFile;
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared};
use rustc_codegen_ssa::back::symbol_export;
@@ -34,8 +32,8 @@ pub const THIN_LTO_KEYS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-keys.bin";
pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
match crate_type {
- CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => true,
- CrateType::Dylib | CrateType::Rlib | CrateType::ProcMacro => false,
+ CrateType::Executable | CrateType::Dylib | CrateType::Staticlib | CrateType::Cdylib => true,
+ CrateType::Rlib | CrateType::ProcMacro => false,
}
}
@@ -75,17 +73,6 @@ fn prepare_lto(
// with either fat or thin LTO
let mut upstream_modules = Vec::new();
if cgcx.lto != Lto::ThinLocal {
- if cgcx.opts.cg.prefer_dynamic {
- diag_handler
- .struct_err("cannot prefer dynamic linking when performing LTO")
- .note(
- "only 'staticlib', 'bin', and 'cdylib' outputs are \
- supported with LTO",
- )
- .emit();
- return Err(FatalError);
- }
-
// Make sure we actually can run LTO
for crate_type in cgcx.crate_types.iter() {
if !crate_type_allows_lto(*crate_type) {
@@ -94,9 +81,25 @@ fn prepare_lto(
static library outputs",
);
return Err(e);
+ } else if *crate_type == CrateType::Dylib {
+ if !cgcx.opts.unstable_opts.dylib_lto {
+ return Err(diag_handler
+ .fatal("lto cannot be used for `dylib` crate type without `-Zdylib-lto`"));
+ }
}
}
+ if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto {
+ diag_handler
+ .struct_err("cannot prefer dynamic linking when performing LTO")
+ .note(
+ "only 'staticlib', 'bin', and 'cdylib' outputs are \
+ supported with LTO",
+ )
+ .emit();
+ return Err(FatalError);
+ }
+
for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() {
let exported_symbols =
cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO");
@@ -575,7 +578,7 @@ pub(crate) fn run_pass_manager(
module: &mut ModuleCodegen<ModuleLlvm>,
thin: bool,
) -> Result<(), FatalError> {
- let _timer = cgcx.prof.extra_verbose_generic_activity("LLVM_lto_optimize", &*module.name);
+ let _timer = cgcx.prof.verbose_generic_activity_with_arg("LLVM_lto_optimize", &*module.name);
let config = cgcx.config(module.kind);
// Now we have one massive module inside of llmod. Time to run the
@@ -597,61 +600,9 @@ pub(crate) fn run_pass_manager(
1,
);
}
- if llvm_util::should_use_new_llvm_pass_manager(
- &config.new_llvm_pass_manager,
- &cgcx.target_arch,
- ) {
- let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
- let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
- write::optimize_with_new_llvm_pass_manager(
- cgcx,
- diag_handler,
- module,
- config,
- opt_level,
- opt_stage,
- )?;
- debug!("lto done");
- return Ok(());
- }
-
- let pm = llvm::LLVMCreatePassManager();
- llvm::LLVMAddAnalysisPasses(module.module_llvm.tm, pm);
-
- if config.verify_llvm_ir {
- let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr().cast());
- llvm::LLVMRustAddPass(pm, pass.unwrap());
- }
-
- let opt_level = config
- .opt_level
- .map(|x| to_llvm_opt_settings(x).0)
- .unwrap_or(llvm::CodeGenOptLevel::None);
- with_llvm_pmb(module.module_llvm.llmod(), config, opt_level, false, &mut |b| {
- if thin {
- llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm);
- } else {
- llvm::LLVMRustPassManagerBuilderPopulateLTOPassManager(
- b, pm, /* Internalize = */ False, /* RunInliner = */ True,
- );
- }
- });
-
- // We always generate bitcode through ThinLTOBuffers,
- // which do not support anonymous globals
- if config.bitcode_needed() {
- let pass = llvm::LLVMRustFindAndCreatePass("name-anon-globals\0".as_ptr().cast());
- llvm::LLVMRustAddPass(pm, pass.unwrap());
- }
-
- if config.verify_llvm_ir {
- let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr().cast());
- llvm::LLVMRustAddPass(pm, pass.unwrap());
- }
-
- llvm::LLVMRunPassManager(pm, module.module_llvm.llmod());
-
- llvm::LLVMDisposePassManager(pm);
+ let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
+ let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
+ write::llvm_optimize(cgcx, diag_handler, module, config, opt_level, opt_stage)?;
}
debug!("lto done");
Ok(())
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index a695df840..11053a8f6 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -21,7 +21,6 @@ use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_errors::{FatalError, Handler, Level};
use rustc_fs_util::{link_or_copy, path_to_c_string};
-use rustc_middle::bug;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath};
use rustc_session::Session;
@@ -417,7 +416,7 @@ fn get_instr_profile_output_path(config: &ModuleConfig) -> Option<CString> {
}
}
-pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
+pub(crate) unsafe fn llvm_optimize(
cgcx: &CodegenContext<LlvmCodegenBackend>,
diag_handler: &Handler,
module: &ModuleCodegen<ModuleLlvm>,
@@ -465,7 +464,7 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
// FIXME: NewPM doesn't provide a facility to pass custom InlineParams.
// We would have to add upstream support for this first, before we can support
// config.inline_threshold and our more aggressive default thresholds.
- let result = llvm::LLVMRustOptimizeWithNewPassManager(
+ let result = llvm::LLVMRustOptimize(
module.module_llvm.llmod(),
&*module.module_llvm.tm,
to_pass_builder_opt_level(opt_level),
@@ -509,18 +508,11 @@ pub(crate) unsafe fn optimize(
let llmod = module.module_llvm.llmod();
let llcx = &*module.module_llvm.llcx;
- let tm = &*module.module_llvm.tm;
let _handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
let module_name = module.name.clone();
let module_name = Some(&module_name[..]);
- if let Some(false) = config.new_llvm_pass_manager && llvm_util::get_version() >= (15, 0, 0) {
- diag_handler.warn(
- "ignoring `-Z new-llvm-pass-manager=no`, which is no longer supported with LLVM 15",
- );
- }
-
if config.emit_no_opt_bc {
let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name);
let out = path_to_c_string(&out);
@@ -528,191 +520,24 @@ pub(crate) unsafe fn optimize(
}
if let Some(opt_level) = config.opt_level {
- if llvm_util::should_use_new_llvm_pass_manager(
- &config.new_llvm_pass_manager,
- &cgcx.target_arch,
- ) {
- let opt_stage = match cgcx.lto {
- Lto::Fat => llvm::OptStage::PreLinkFatLTO,
- Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO,
- _ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
- _ => llvm::OptStage::PreLinkNoLTO,
- };
- return optimize_with_new_llvm_pass_manager(
- cgcx,
- diag_handler,
- module,
- config,
- opt_level,
- opt_stage,
- );
- }
-
- if cgcx.prof.llvm_recording_enabled() {
- diag_handler
- .warn("`-Z self-profile-events = llvm` requires `-Z new-llvm-pass-manager`");
- }
-
- // Create the two optimizing pass managers. These mirror what clang
- // does, and are by populated by LLVM's default PassManagerBuilder.
- // Each manager has a different set of passes, but they also share
- // some common passes.
- let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
- let mpm = llvm::LLVMCreatePassManager();
-
- {
- let find_pass = |pass_name: &str| {
- let pass_name = SmallCStr::new(pass_name);
- llvm::LLVMRustFindAndCreatePass(pass_name.as_ptr())
- };
-
- if config.verify_llvm_ir {
- // Verification should run as the very first pass.
- llvm::LLVMRustAddPass(fpm, find_pass("verify").unwrap());
- }
-
- let mut extra_passes = Vec::new();
- let mut have_name_anon_globals_pass = false;
-
- for pass_name in &config.passes {
- if pass_name == "lint" {
- // Linting should also be performed early, directly on the generated IR.
- llvm::LLVMRustAddPass(fpm, find_pass("lint").unwrap());
- continue;
- }
-
- if let Some(pass) = find_pass(pass_name) {
- extra_passes.push(pass);
- } else {
- diag_handler.warn(&format!("unknown pass `{}`, ignoring", pass_name));
- }
-
- if pass_name == "name-anon-globals" {
- have_name_anon_globals_pass = true;
- }
- }
-
- // Instrumentation must be inserted before optimization,
- // otherwise LLVM may optimize some functions away which
- // breaks llvm-cov.
- //
- // This mirrors what Clang does in lib/CodeGen/BackendUtil.cpp.
- if config.instrument_gcov {
- llvm::LLVMRustAddPass(mpm, find_pass("insert-gcov-profiling").unwrap());
- }
- if config.instrument_coverage {
- llvm::LLVMRustAddPass(mpm, find_pass("instrprof").unwrap());
- }
- if config.debug_info_for_profiling {
- llvm::LLVMRustAddPass(mpm, find_pass("add-discriminators").unwrap());
- }
-
- add_sanitizer_passes(config, &mut extra_passes);
-
- // Some options cause LLVM bitcode to be emitted, which uses ThinLTOBuffers, so we need
- // to make sure we run LLVM's NameAnonGlobals pass when emitting bitcode; otherwise
- // we'll get errors in LLVM.
- let using_thin_buffers = config.bitcode_needed();
- if !config.no_prepopulate_passes {
- llvm::LLVMAddAnalysisPasses(tm, fpm);
- llvm::LLVMAddAnalysisPasses(tm, mpm);
- let opt_level = to_llvm_opt_settings(opt_level).0;
- let prepare_for_thin_lto = cgcx.lto == Lto::Thin
- || cgcx.lto == Lto::ThinLocal
- || (cgcx.lto != Lto::Fat && cgcx.opts.cg.linker_plugin_lto.enabled());
- with_llvm_pmb(llmod, config, opt_level, prepare_for_thin_lto, &mut |b| {
- llvm::LLVMRustAddLastExtensionPasses(
- b,
- extra_passes.as_ptr(),
- extra_passes.len() as size_t,
- );
- llvm::LLVMRustPassManagerBuilderPopulateFunctionPassManager(b, fpm);
- llvm::LLVMRustPassManagerBuilderPopulateModulePassManager(b, mpm);
- });
-
- have_name_anon_globals_pass = have_name_anon_globals_pass || prepare_for_thin_lto;
- if using_thin_buffers && !prepare_for_thin_lto {
- llvm::LLVMRustAddPass(mpm, find_pass("name-anon-globals").unwrap());
- have_name_anon_globals_pass = true;
- }
- } else {
- // If we don't use the standard pipeline, directly populate the MPM
- // with the extra passes.
- for pass in extra_passes {
- llvm::LLVMRustAddPass(mpm, pass);
- }
- }
-
- if using_thin_buffers && !have_name_anon_globals_pass {
- // As described above, this will probably cause an error in LLVM
- if config.no_prepopulate_passes {
- diag_handler.err(
- "The current compilation is going to use thin LTO buffers \
- without running LLVM's NameAnonGlobals pass. \
- This will likely cause errors in LLVM. Consider adding \
- -C passes=name-anon-globals to the compiler command line.",
- );
- } else {
- bug!(
- "We are using thin LTO buffers without running the NameAnonGlobals pass. \
- This will likely cause errors in LLVM and should never happen."
- );
- }
- }
- }
-
- diag_handler.abort_if_errors();
-
- // Finally, run the actual optimization passes
- {
- let _timer = cgcx.prof.extra_verbose_generic_activity(
- "LLVM_module_optimize_function_passes",
- &*module.name,
- );
- llvm::LLVMRustRunFunctionPassManager(fpm, llmod);
- }
- {
- let _timer = cgcx.prof.extra_verbose_generic_activity(
- "LLVM_module_optimize_module_passes",
- &*module.name,
- );
- llvm::LLVMRunPassManager(mpm, llmod);
- }
-
- // Deallocate managers that we're now done with
- llvm::LLVMDisposePassManager(fpm);
- llvm::LLVMDisposePassManager(mpm);
+ let opt_stage = match cgcx.lto {
+ Lto::Fat => llvm::OptStage::PreLinkFatLTO,
+ Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO,
+ _ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
+ _ => llvm::OptStage::PreLinkNoLTO,
+ };
+ return llvm_optimize(cgcx, diag_handler, module, config, opt_level, opt_stage);
}
Ok(())
}
-unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static mut llvm::Pass>) {
- if config.sanitizer.contains(SanitizerSet::ADDRESS) {
- let recover = config.sanitizer_recover.contains(SanitizerSet::ADDRESS);
- passes.push(llvm::LLVMRustCreateAddressSanitizerFunctionPass(recover));
- passes.push(llvm::LLVMRustCreateModuleAddressSanitizerPass(recover));
- }
- if config.sanitizer.contains(SanitizerSet::MEMORY) {
- let track_origins = config.sanitizer_memory_track_origins as c_int;
- let recover = config.sanitizer_recover.contains(SanitizerSet::MEMORY);
- passes.push(llvm::LLVMRustCreateMemorySanitizerPass(track_origins, recover));
- }
- if config.sanitizer.contains(SanitizerSet::THREAD) {
- passes.push(llvm::LLVMRustCreateThreadSanitizerPass());
- }
- if config.sanitizer.contains(SanitizerSet::HWADDRESS) {
- let recover = config.sanitizer_recover.contains(SanitizerSet::HWADDRESS);
- passes.push(llvm::LLVMRustCreateHWAddressSanitizerPass(recover));
- }
-}
-
pub(crate) fn link(
cgcx: &CodegenContext<LlvmCodegenBackend>,
diag_handler: &Handler,
mut modules: Vec<ModuleCodegen<ModuleLlvm>>,
) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
use super::lto::{Linker, ModuleBuffer};
- // Sort the modules by name to ensure to ensure deterministic behavior.
+ // Sort the modules by name to ensure deterministic behavior.
modules.sort_by(|a, b| a.name.cmp(&b.name));
let (first, elements) =
modules.split_first().expect("Bug! modules must contain at least one module.");
@@ -1072,72 +897,6 @@ unsafe fn embed_bitcode(
}
}
-pub unsafe fn with_llvm_pmb(
- llmod: &llvm::Module,
- config: &ModuleConfig,
- opt_level: llvm::CodeGenOptLevel,
- prepare_for_thin_lto: bool,
- f: &mut dyn FnMut(&llvm::PassManagerBuilder),
-) {
- use std::ptr;
-
- // Create the PassManagerBuilder for LLVM. We configure it with
- // reasonable defaults and prepare it to actually populate the pass
- // manager.
- let builder = llvm::LLVMRustPassManagerBuilderCreate();
- let opt_size = config.opt_size.map_or(llvm::CodeGenOptSizeNone, |x| to_llvm_opt_settings(x).1);
- let inline_threshold = config.inline_threshold;
- let pgo_gen_path = get_pgo_gen_path(config);
- let pgo_use_path = get_pgo_use_path(config);
- let pgo_sample_use_path = get_pgo_sample_use_path(config);
-
- llvm::LLVMRustConfigurePassManagerBuilder(
- builder,
- opt_level,
- config.merge_functions,
- config.vectorize_slp,
- config.vectorize_loop,
- prepare_for_thin_lto,
- pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
- pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
- pgo_sample_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
- opt_size as c_int,
- );
-
- llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins);
-
- // Here we match what clang does (kinda). For O0 we only inline
- // always-inline functions (but don't add lifetime intrinsics), at O1 we
- // inline with lifetime intrinsics, and O2+ we add an inliner with a
- // thresholds copied from clang.
- match (opt_level, opt_size, inline_threshold) {
- (.., Some(t)) => {
- llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, t);
- }
- (llvm::CodeGenOptLevel::Aggressive, ..) => {
- llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 275);
- }
- (_, llvm::CodeGenOptSizeDefault, _) => {
- llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 75);
- }
- (_, llvm::CodeGenOptSizeAggressive, _) => {
- llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 25);
- }
- (llvm::CodeGenOptLevel::None, ..) => {
- llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
- }
- (llvm::CodeGenOptLevel::Less, ..) => {
- llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
- }
- (llvm::CodeGenOptLevel::Default, ..) => {
- llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 225);
- }
- }
-
- f(builder);
- llvm::LLVMRustPassManagerBuilderDispose(builder);
-}
-
// Create a `__imp_<symbol> = &symbol` global for every public static `symbol`.
// This is required to satisfy `dllimport` references to static data in .rlibs
// when using MSVC linker. We do this only for data, as linker can fix up
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index 86f92dc02..5b2bbdb4b 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -19,6 +19,8 @@ use crate::context::CodegenCx;
use crate::llvm;
use crate::value::Value;
+use cstr::cstr;
+
use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
use rustc_codegen_ssa::mono_item::MonoItemExt;
use rustc_codegen_ssa::traits::*;
@@ -107,11 +109,14 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen
}
// Create the llvm.used and llvm.compiler.used variables.
- if !cx.used_statics().borrow().is_empty() {
- cx.create_used_variable()
+ if !cx.used_statics.borrow().is_empty() {
+ cx.create_used_variable_impl(cstr!("llvm.used"), &*cx.used_statics.borrow());
}
- if !cx.compiler_used_statics().borrow().is_empty() {
- cx.create_compiler_used_variable()
+ if !cx.compiler_used_statics.borrow().is_empty() {
+ cx.create_used_variable_impl(
+ cstr!("llvm.compiler.used"),
+ &*cx.compiler_used_statics.borrow(),
+ );
}
// Run replace-all-uses-with for statics that need it. This must
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 63b63c6a1..fca43a0d8 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -1,14 +1,14 @@
+use crate::abi::FnAbiLlvmExt;
use crate::attributes;
use crate::common::Funclet;
use crate::context::CodegenCx;
-use crate::llvm::{self, BasicBlock, False};
-use crate::llvm::{AtomicOrdering, AtomicRmwBinOp, SynchronizationScope};
+use crate::llvm::{self, AtomicOrdering, AtomicRmwBinOp, BasicBlock};
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
use cstr::cstr;
use libc::{c_char, c_uint};
-use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, TypeKind};
+use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, SynchronizationScope, TypeKind};
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::*;
@@ -215,6 +215,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
fn invoke(
&mut self,
llty: &'ll Type,
+ fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
llfn: &'ll Value,
args: &[&'ll Value],
then: &'ll BasicBlock,
@@ -227,7 +228,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
let bundle = funclet.map(|funclet| funclet.bundle());
let bundle = bundle.as_ref().map(|b| &*b.raw);
- unsafe {
+ let invoke = unsafe {
llvm::LLVMRustBuildInvoke(
self.llbuilder,
llty,
@@ -239,7 +240,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
bundle,
UNNAMED,
)
+ };
+ if let Some(fn_abi) = fn_abi {
+ fn_abi.apply_attrs_callsite(self, invoke);
}
+ invoke
}
fn unreachable(&mut self) {
@@ -406,20 +411,17 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
fn alloca(&mut self, ty: &'ll Type, align: Align) -> &'ll Value {
let mut bx = Builder::with_cx(self.cx);
bx.position_at_start(unsafe { llvm::LLVMGetFirstBasicBlock(self.llfn()) });
- bx.dynamic_alloca(ty, align)
- }
-
- fn dynamic_alloca(&mut self, ty: &'ll Type, align: Align) -> &'ll Value {
unsafe {
- let alloca = llvm::LLVMBuildAlloca(self.llbuilder, ty, UNNAMED);
+ let alloca = llvm::LLVMBuildAlloca(bx.llbuilder, ty, UNNAMED);
llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint);
alloca
}
}
- fn array_alloca(&mut self, ty: &'ll Type, len: &'ll Value, align: Align) -> &'ll Value {
+ fn byte_array_alloca(&mut self, len: &'ll Value, align: Align) -> &'ll Value {
unsafe {
- let alloca = llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, UNNAMED);
+ let alloca =
+ llvm::LLVMBuildArrayAlloca(self.llbuilder, self.cx().type_i8(), len, UNNAMED);
llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint);
alloca
}
@@ -1042,15 +1044,17 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
) -> &'ll Value {
let weak = if weak { llvm::True } else { llvm::False };
unsafe {
- llvm::LLVMRustBuildAtomicCmpXchg(
+ let value = llvm::LLVMBuildAtomicCmpXchg(
self.llbuilder,
dst,
cmp,
src,
AtomicOrdering::from_generic(order),
AtomicOrdering::from_generic(failure_order),
- weak,
- )
+ llvm::False, // SingleThreaded
+ );
+ llvm::LLVMSetWeak(value, weak);
+ value
}
}
fn atomic_rmw(
@@ -1067,7 +1071,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
dst,
src,
AtomicOrdering::from_generic(order),
- False,
+ llvm::False, // SingleThreaded
)
}
}
@@ -1075,13 +1079,18 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
fn atomic_fence(
&mut self,
order: rustc_codegen_ssa::common::AtomicOrdering,
- scope: rustc_codegen_ssa::common::SynchronizationScope,
+ scope: SynchronizationScope,
) {
+ let single_threaded = match scope {
+ SynchronizationScope::SingleThread => llvm::True,
+ SynchronizationScope::CrossThread => llvm::False,
+ };
unsafe {
- llvm::LLVMRustBuildAtomicFence(
+ llvm::LLVMBuildFence(
self.llbuilder,
AtomicOrdering::from_generic(order),
- SynchronizationScope::from_generic(scope),
+ single_threaded,
+ UNNAMED,
);
}
}
@@ -1139,6 +1148,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
fn call(
&mut self,
llty: &'ll Type,
+ fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
llfn: &'ll Value,
args: &[&'ll Value],
funclet: Option<&Funclet<'ll>>,
@@ -1149,7 +1159,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
let bundle = funclet.map(|funclet| funclet.bundle());
let bundle = bundle.as_ref().map(|b| &*b.raw);
- unsafe {
+ let call = unsafe {
llvm::LLVMRustBuildCall(
self.llbuilder,
llty,
@@ -1158,7 +1168,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
args.len() as c_uint,
bundle,
)
+ };
+ if let Some(fn_abi) = fn_abi {
+ fn_abi.apply_attrs_callsite(self, call);
}
+ call
}
fn zext(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
@@ -1391,7 +1405,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, f, args, None)
+ self.call(ty, None, f, args, None)
}
fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) {
@@ -1453,7 +1467,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), f, &[val], None)
+ self.call(self.type_func(&[src_ty], dest_ty), None, f, &[val], None)
}
pub(crate) fn landing_pad(
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index b83c1e8f0..6f0d1b7ce 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -179,7 +179,8 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
// MinGW: For backward compatibility we rely on the linker to decide whether it
// should use dllimport for functions.
if cx.use_dll_storage_attrs
- && tcx.is_dllimport_foreign_item(instance_def_id)
+ && let Some(library) = tcx.native_library(instance_def_id)
+ && library.kind.is_dllimport()
&& !matches!(tcx.sess.target.env.as_ref(), "gnu" | "uclibc")
{
llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index a559f7f3d..dd3c43ba5 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -332,7 +332,10 @@ impl<'ll> CodegenCx<'ll, '_> {
}
}
- if self.use_dll_storage_attrs && self.tcx.is_dllimport_foreign_item(def_id) {
+ if self.use_dll_storage_attrs
+ && let Some(library) = self.tcx.native_library(def_id)
+ && library.kind.is_dllimport()
+ {
// For foreign (native) libs we know the exact storage type to use.
unsafe {
llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport);
@@ -552,7 +555,7 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
// `#[used(compiler)]` is explicitly requested. This is to avoid similar breakage
// on other targets, in particular MachO targets have *their* static constructor
// lists broken if `llvm.compiler.used` is emitted rather than llvm.used. However,
- // that check happens when assigning the `CodegenFnAttrFlags` in `rustc_typeck`,
+ // that check happens when assigning the `CodegenFnAttrFlags` in `rustc_hir_analysis`,
// so we don't need to take care of it here.
self.add_compiler_used_global(g);
}
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 67ffc7cb9..79ddfd884 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -154,6 +154,11 @@ pub unsafe fn create_module<'ll>(
target_data_layout = target_data_layout.replace("-p10:8:8-p20:8:8", "");
}
}
+ if llvm_version < (16, 0, 0) {
+ if sess.target.arch == "s390x" {
+ target_data_layout = target_data_layout.replace("-v128:64", "");
+ }
+ }
// Ensure the data-layout values hardcoded remain the defaults.
if sess.target.is_builtin {
@@ -453,7 +458,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
self.coverage_cx.as_ref()
}
- fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) {
+ pub(crate) fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) {
let section = cstr!("llvm.metadata");
let array = self.const_array(self.type_ptr_to(self.type_i8()), values);
@@ -551,14 +556,6 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
self.codegen_unit
}
- fn used_statics(&self) -> &RefCell<Vec<&'ll Value>> {
- &self.used_statics
- }
-
- fn compiler_used_statics(&self) -> &RefCell<Vec<&'ll Value>> {
- &self.compiler_used_statics
- }
-
fn set_frame_pointer_type(&self, llfn: &'ll Value) {
if let Some(attr) = attributes::frame_pointer_type_attr(self) {
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[attr]);
@@ -572,17 +569,6 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &attrs);
}
- fn create_used_variable(&self) {
- self.create_used_variable_impl(cstr!("llvm.used"), &*self.used_statics.borrow());
- }
-
- fn create_compiler_used_variable(&self) {
- self.create_used_variable_impl(
- cstr!("llvm.compiler.used"),
- &*self.compiler_used_statics.borrow(),
- );
- }
-
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
if self.get_declared_value("main").is_none() {
Some(self.declare_cfn("main", llvm::UnnamedAddr::Global, fn_type))
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 0d1df6fb1..433f04320 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -129,7 +129,7 @@ impl CoverageMapGenerator {
// LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
// requires setting the first filename to the compilation directory.
// Since rustc generates coverage maps with relative paths, the
- // compilation directory can be combined with the the relative paths
+ // compilation directory can be combined with the relative paths
// to get absolute paths, if needed.
let working_dir = tcx
.sess
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 0f663a267..f79ef1172 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -32,6 +32,7 @@ fn declare_raw_fn<'ll>(
name: &str,
callconv: llvm::CallConv,
unnamed: llvm::UnnamedAddr,
+ visibility: llvm::Visibility,
ty: &'ll Type,
) -> &'ll Value {
debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
@@ -41,6 +42,7 @@ fn declare_raw_fn<'ll>(
llvm::SetFunctionCallConv(llfn, callconv);
llvm::SetUnnamedAddress(llfn, unnamed);
+ llvm::set_visibility(llfn, visibility);
let mut attrs = SmallVec::<[_; 4]>::new();
@@ -78,7 +80,14 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
unnamed: llvm::UnnamedAddr,
fn_type: &'ll Type,
) -> &'ll Value {
- declare_raw_fn(self, name, llvm::CCallConv, unnamed, fn_type)
+ // Declare C ABI functions with the visibility used by C by default.
+ let visibility = if self.tcx.sess.target.default_hidden_visibility {
+ llvm::Visibility::Hidden
+ } else {
+ llvm::Visibility::Default
+ };
+
+ declare_raw_fn(self, name, llvm::CCallConv, unnamed, visibility, fn_type)
}
/// Declare a Rust function.
@@ -95,6 +104,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
name,
fn_abi.llvm_cconv(),
llvm::UnnamedAddr::Global,
+ llvm::Visibility::Default,
fn_abi.llvm_type(self),
);
fn_abi.apply_attrs_llfn(self, llfn);
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index a640de42a..825011941 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -108,6 +108,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
let (simple_ty, simple_fn) = simple.unwrap();
self.call(
simple_ty,
+ None,
simple_fn,
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
None,
@@ -435,7 +436,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, try_func, &[data], None);
+ bx.call(try_func_ty, 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;
@@ -534,7 +535,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, try_func, &[data], normal, catchswitch, None);
+ bx.invoke(try_func_ty, None, try_func, &[data], normal, catchswitch, None);
bx.switch_to_block(normal);
bx.ret(bx.const_i32(0));
@@ -578,7 +579,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, catch_func, &[data, ptr], Some(&funclet));
+ bx.call(catch_ty, None, catch_func, &[data, ptr], Some(&funclet));
bx.catch_ret(&funclet, caught);
// The flag value of 64 indicates a "catch-all".
@@ -586,7 +587,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, catch_func, &[data, null], Some(&funclet));
+ bx.call(catch_ty, None, catch_func, &[data, null], Some(&funclet));
bx.catch_ret(&funclet, caught);
bx.switch_to_block(caught);
@@ -595,7 +596,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, llfn, &[try_func, data, catch_func], None);
+ let ret = bx.call(llty, None, llfn, &[try_func, data, catch_func], None);
let i32_align = bx.tcx().data_layout.i32_align.abi;
bx.store(ret, dest, i32_align);
}
@@ -638,7 +639,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, try_func, &[data], then, catch, None);
+ bx.invoke(try_func_ty, None, try_func, &[data], then, catch, None);
bx.switch_to_block(then);
bx.ret(bx.const_i32(0));
@@ -656,13 +657,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, catch_func, &[data, ptr], None);
+ bx.call(catch_ty, 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, llfn, &[try_func, data, catch_func], None);
+ let ret = bx.call(llty, None, llfn, &[try_func, data, catch_func], None);
let i32_align = bx.tcx().data_layout.i32_align.abi;
bx.store(ret, dest, i32_align);
}
@@ -702,7 +703,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, try_func, &[data], then, catch, None);
+ bx.invoke(try_func_ty, None, try_func, &[data], then, catch, None);
bx.switch_to_block(then);
bx.ret(bx.const_i32(0));
@@ -741,13 +742,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, catch_func, &[data, catch_data], None);
+ bx.call(catch_ty, 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, llfn, &[try_func, data, catch_func], None);
+ let ret = bx.call(llty, None, llfn, &[try_func, data, catch_func], None);
let i32_align = bx.tcx().data_layout.i32_align.abi;
bx.store(ret, dest, i32_align);
}
@@ -1217,8 +1218,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
};
let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str);
let f = bx.declare_cfn(llvm_name, llvm::UnnamedAddr::No, fn_ty);
- let c =
- bx.call(fn_ty, f, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None);
+ let c = bx.call(
+ fn_ty,
+ None,
+ f,
+ &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
+ None,
+ );
Ok(c)
}
@@ -1417,8 +1423,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
llvm_elem_vec_ty,
);
let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
- let v =
- bx.call(fn_ty, f, &[args[1].immediate(), alignment, mask, args[0].immediate()], None);
+ let v = bx.call(
+ fn_ty,
+ None,
+ f,
+ &[args[1].immediate(), alignment, mask, args[0].immediate()],
+ None,
+ );
return Ok(v);
}
@@ -1543,8 +1554,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
let fn_ty =
bx.type_func(&[llvm_elem_vec_ty, llvm_pointer_vec_ty, alignment_ty, mask_ty], ret_t);
let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
- let v =
- bx.call(fn_ty, f, &[args[0].immediate(), args[1].immediate(), alignment, mask], None);
+ let v = bx.call(
+ fn_ty,
+ None,
+ f,
+ &[args[0].immediate(), args[1].immediate(), alignment, mask],
+ None,
+ );
return Ok(v);
}
@@ -1992,7 +2008,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
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, f, &[lhs, rhs], None);
+ let v = bx.call(fn_ty, 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 42c65e04e..89c7e51d0 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -7,7 +7,6 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(hash_raw_entry)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(extern_types)]
#![feature(once_cell)]
#![feature(iter_intersperse)]
@@ -132,12 +131,6 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
) -> TargetMachineFactoryFn<Self> {
back::write::target_machine_factory(sess, optlvl, target_features)
}
- fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str {
- llvm_util::target_cpu(sess)
- }
- fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str> {
- llvm_util::tune_cpu(sess)
- }
fn spawn_thread<F, T>(time_trace: bool, f: F) -> std::thread::JoinHandle<T>
where
@@ -171,7 +164,6 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
impl WriteBackendMethods for LlvmCodegenBackend {
type Module = ModuleLlvm;
type ModuleBuffer = back::lto::ModuleBuffer;
- type Context = llvm::Context;
type TargetMachine = &'static mut llvm::TargetMachine;
type ThinData = back::lto::ThinData;
type ThinBuffer = back::lto::ThinBuffer;
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index ce27dc5a5..42cb694c0 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -400,27 +400,6 @@ impl AtomicOrdering {
}
}
-/// LLVMRustSynchronizationScope
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub enum SynchronizationScope {
- SingleThread,
- CrossThread,
-}
-
-impl SynchronizationScope {
- pub fn from_generic(sc: rustc_codegen_ssa::common::SynchronizationScope) -> Self {
- match sc {
- rustc_codegen_ssa::common::SynchronizationScope::SingleThread => {
- SynchronizationScope::SingleThread
- }
- rustc_codegen_ssa::common::SynchronizationScope::CrossThread => {
- SynchronizationScope::CrossThread
- }
- }
- }
-}
-
/// LLVMRustFileType
#[derive(Copy, Clone)]
#[repr(C)]
@@ -1782,16 +1761,18 @@ extern "C" {
Order: AtomicOrdering,
) -> &'a Value;
- pub fn LLVMRustBuildAtomicCmpXchg<'a>(
+ pub fn LLVMBuildAtomicCmpXchg<'a>(
B: &Builder<'a>,
LHS: &'a Value,
CMP: &'a Value,
RHS: &'a Value,
Order: AtomicOrdering,
FailureOrder: AtomicOrdering,
- Weak: Bool,
+ SingleThreaded: Bool,
) -> &'a Value;
+ pub fn LLVMSetWeak(CmpXchgInst: &Value, IsWeak: Bool);
+
pub fn LLVMBuildAtomicRMW<'a>(
B: &Builder<'a>,
Op: AtomicRmwBinOp,
@@ -1801,27 +1782,19 @@ extern "C" {
SingleThreaded: Bool,
) -> &'a Value;
- pub fn LLVMRustBuildAtomicFence(
- B: &Builder<'_>,
+ pub fn LLVMBuildFence<'a>(
+ B: &Builder<'a>,
Order: AtomicOrdering,
- Scope: SynchronizationScope,
- );
+ SingleThreaded: Bool,
+ Name: *const c_char,
+ ) -> &'a Value;
/// Writes a module to the specified path. Returns 0 on success.
pub fn LLVMWriteBitcodeToFile(M: &Module, Path: *const c_char) -> c_int;
- /// Creates a pass manager.
+ /// Creates a legacy pass manager -- only used for final codegen.
pub fn LLVMCreatePassManager<'a>() -> &'a mut PassManager<'a>;
- /// Creates a function-by-function pass manager
- pub fn LLVMCreateFunctionPassManagerForModule(M: &Module) -> &mut PassManager<'_>;
-
- /// Disposes a pass manager.
- pub fn LLVMDisposePassManager<'a>(PM: &'a mut PassManager<'a>);
-
- /// Runs a pass manager on a module.
- pub fn LLVMRunPassManager<'a>(PM: &PassManager<'a>, M: &'a Module) -> Bool;
-
pub fn LLVMInitializePasses();
pub fn LLVMTimeTraceProfilerInitialize();
@@ -1832,32 +1805,6 @@ extern "C" {
pub fn LLVMAddAnalysisPasses<'a>(T: &'a TargetMachine, PM: &PassManager<'a>);
- pub fn LLVMRustPassManagerBuilderCreate() -> &'static mut PassManagerBuilder;
- pub fn LLVMRustPassManagerBuilderDispose(PMB: &'static mut PassManagerBuilder);
- pub fn LLVMRustPassManagerBuilderUseInlinerWithThreshold(
- PMB: &PassManagerBuilder,
- threshold: c_uint,
- );
- pub fn LLVMRustPassManagerBuilderPopulateModulePassManager(
- PMB: &PassManagerBuilder,
- PM: &PassManager<'_>,
- );
-
- pub fn LLVMRustPassManagerBuilderPopulateFunctionPassManager(
- PMB: &PassManagerBuilder,
- PM: &PassManager<'_>,
- );
- pub fn LLVMRustPassManagerBuilderPopulateLTOPassManager(
- PMB: &PassManagerBuilder,
- PM: &PassManager<'_>,
- Internalize: Bool,
- RunInliner: Bool,
- );
- pub fn LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
- PMB: &PassManagerBuilder,
- PM: &PassManager<'_>,
- );
-
pub fn LLVMGetHostCPUFeatures() -> *mut c_char;
pub fn LLVMDisposeMessage(message: *mut c_char);
@@ -2262,22 +2209,6 @@ extern "C" {
pub fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>;
- pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> Option<&'static mut Pass>;
- pub fn LLVMRustCreateAddressSanitizerFunctionPass(Recover: bool) -> &'static mut Pass;
- pub fn LLVMRustCreateModuleAddressSanitizerPass(Recover: bool) -> &'static mut Pass;
- pub fn LLVMRustCreateMemorySanitizerPass(
- TrackOrigins: c_int,
- Recover: bool,
- ) -> &'static mut Pass;
- pub fn LLVMRustCreateThreadSanitizerPass() -> &'static mut Pass;
- pub fn LLVMRustCreateHWAddressSanitizerPass(Recover: bool) -> &'static mut Pass;
- pub fn LLVMRustAddPass(PM: &PassManager<'_>, Pass: &'static mut Pass);
- pub fn LLVMRustAddLastExtensionPasses(
- PMB: &PassManagerBuilder,
- Passes: *const &'static mut Pass,
- NumPasses: size_t,
- );
-
pub fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool;
pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine);
@@ -2311,29 +2242,11 @@ extern "C" {
SplitDwarfFile: *const c_char,
) -> Option<&'static mut TargetMachine>;
pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine);
- pub fn LLVMRustAddBuilderLibraryInfo<'a>(
- PMB: &'a PassManagerBuilder,
- M: &'a Module,
- DisableSimplifyLibCalls: bool,
- );
- pub fn LLVMRustConfigurePassManagerBuilder(
- PMB: &PassManagerBuilder,
- OptLevel: CodeGenOptLevel,
- MergeFunctions: bool,
- SLPVectorize: bool,
- LoopVectorize: bool,
- PrepareForThinLTO: bool,
- PGOGenPath: *const c_char,
- PGOUsePath: *const c_char,
- PGOSampleUsePath: *const c_char,
- SizeLevel: c_int,
- );
pub fn LLVMRustAddLibraryInfo<'a>(
PM: &PassManager<'a>,
M: &'a Module,
DisableSimplifyLibCalls: bool,
);
- pub fn LLVMRustRunFunctionPassManager<'a>(PM: &PassManager<'a>, M: &'a Module);
pub fn LLVMRustWriteOutputFile<'a>(
T: &'a TargetMachine,
PM: &PassManager<'a>,
@@ -2342,7 +2255,7 @@ extern "C" {
DwoOutput: *const c_char,
FileType: FileType,
) -> LLVMRustResult;
- pub fn LLVMRustOptimizeWithNewPassManager<'a>(
+ pub fn LLVMRustOptimize<'a>(
M: &'a Module,
TM: &'a TargetMachine,
OptLevel: PassBuilderOptLevel,
@@ -2380,7 +2293,6 @@ extern "C" {
pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char);
pub fn LLVMRustPrintPasses();
pub fn LLVMRustSetNormalizedTarget(M: &Module, triple: *const c_char);
- pub fn LLVMRustAddAlwaysInlinePass(P: &PassManagerBuilder, AddLifetimes: bool);
pub fn LLVMRustRunRestrictionPass(M: &Module, syms: *const *const c_char, len: size_t);
pub fn LLVMRustOpenArchive(path: *const c_char) -> Option<&'static mut Archive>;
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 60707a1c3..2fd58567c 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -1,7 +1,6 @@
use crate::back::write::create_informational_target_machine;
-use crate::{llvm, llvm_util};
+use crate::llvm;
use libc::c_int;
-use libloading::Library;
use rustc_codegen_ssa::target_features::{
supported_target_features, tied_target_features, RUSTC_SPECIFIC_FEATURES,
};
@@ -16,7 +15,6 @@ use rustc_target::spec::{MergeFunctions, PanicStrategy};
use smallvec::{smallvec, SmallVec};
use std::ffi::{CStr, CString};
-use std::mem;
use std::path::Path;
use std::ptr;
use std::slice;
@@ -120,22 +118,6 @@ unsafe fn configure_llvm(sess: &Session) {
llvm::LLVMInitializePasses();
- // Use the legacy plugin registration if we don't use the new pass manager
- if !should_use_new_llvm_pass_manager(
- &sess.opts.unstable_opts.new_llvm_pass_manager,
- &sess.target.arch,
- ) {
- // Register LLVM plugins by loading them into the compiler process.
- for plugin in &sess.opts.unstable_opts.llvm_plugins {
- let lib = Library::new(plugin).unwrap_or_else(|e| bug!("couldn't load plugin: {}", e));
- debug!("LLVM plugin loaded successfully {:?} ({})", lib, plugin);
-
- // Intentionally leak the dynamic library. We can't ever unload it
- // since the library can make things that will live arbitrarily long.
- mem::forget(lib);
- }
- }
-
rustc_llvm::initialize_available_targets();
llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr());
@@ -539,19 +521,3 @@ pub fn tune_cpu(sess: &Session) -> Option<&str> {
let name = sess.opts.unstable_opts.tune_cpu.as_ref()?;
Some(handle_native(name))
}
-
-pub(crate) fn should_use_new_llvm_pass_manager(user_opt: &Option<bool>, target_arch: &str) -> bool {
- // The new pass manager is enabled by default for LLVM >= 13.
- // This matches Clang, which also enables it since Clang 13.
-
- // Since LLVM 15, the legacy pass manager is no longer supported.
- if llvm_util::get_version() >= (15, 0, 0) {
- return true;
- }
-
- // There are some perf issues with the new pass manager when targeting
- // s390x with LLVM 13, so enable the new pass manager only with LLVM 14.
- // See https://github.com/rust-lang/rust/issues/89609.
- let min_version = if target_arch == "s390x" { 14 } else { 13 };
- user_opt.unwrap_or_else(|| llvm_util::get_version() >= (min_version, 0, 0))
-}
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 6cce95427..0dc0dee86 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -11,7 +11,7 @@ use rustc_metadata::find_native_static_library;
use rustc_metadata::fs::{emit_metadata, METADATA_FILENAME};
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::SymbolExportKind;
-use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
+use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Lto, Strip};
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
use rustc_session::cstore::DllImport;
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
@@ -23,20 +23,23 @@ 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::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
-use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};
+use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy};
+use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, Target};
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
use super::command::Command;
use super::linker::{self, Linker};
use super::metadata::{create_rmeta_file, MetadataPosition};
use super::rpath::{self, RPathConfig};
-use crate::{looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib};
+use crate::{
+ errors, looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib,
+};
use cc::windows_registry;
use regex::Regex;
use tempfile::Builder as TempFileBuilder;
+use itertools::Itertools;
use std::borrow::Borrow;
use std::cell::OnceCell;
use std::collections::BTreeSet;
@@ -93,7 +96,7 @@ pub fn link_binary<'a>(
let tmpdir = TempFileBuilder::new()
.prefix("rustc")
.tempdir()
- .unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err)));
+ .unwrap_or_else(|error| sess.emit_fatal(errors::CreateTempDir { error }));
let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps);
let out_filename = out_filename(
sess,
@@ -206,11 +209,29 @@ pub fn link_binary<'a>(
}
pub fn each_linked_rlib(
+ sess: &Session,
info: &CrateInfo,
f: &mut dyn FnMut(CrateNum, &Path),
-) -> Result<(), String> {
+) -> Result<(), errors::LinkRlibError> {
let crates = info.used_crates.iter();
let mut fmts = None;
+
+ let lto_active = matches!(sess.lto(), Lto::Fat | Lto::Thin);
+ if lto_active {
+ for combination in info.dependency_formats.iter().combinations(2) {
+ let (ty1, list1) = &combination[0];
+ let (ty2, list2) = &combination[1];
+ if list1 != list2 {
+ return Err(errors::LinkRlibError::IncompatibleDependencyFormats {
+ ty1: format!("{ty1:?}"),
+ ty2: format!("{ty2:?}"),
+ list1: format!("{list1:?}"),
+ list2: format!("{list2:?}"),
+ });
+ }
+ }
+ }
+
for (ty, list) in info.dependency_formats.iter() {
match ty {
CrateType::Executable
@@ -220,30 +241,31 @@ pub fn each_linked_rlib(
fmts = Some(list);
break;
}
+ CrateType::Dylib if lto_active => {
+ fmts = Some(list);
+ break;
+ }
_ => {}
}
}
let Some(fmts) = fmts else {
- return Err("could not find formats for rlibs".to_string());
+ return Err(errors::LinkRlibError::MissingFormat);
};
for &cnum in crates {
match fmts.get(cnum.as_usize() - 1) {
Some(&Linkage::NotLinked | &Linkage::IncludedFromDylib) => continue,
Some(_) => {}
- None => return Err("could not find formats for rlibs".to_string()),
+ None => return Err(errors::LinkRlibError::MissingFormat),
}
- let name = info.crate_name[&cnum];
+ let crate_name = info.crate_name[&cnum];
let used_crate_source = &info.used_crate_source[&cnum];
if let Some((path, _)) = &used_crate_source.rlib {
f(cnum, &path);
} else {
if used_crate_source.rmeta.is_some() {
- return Err(format!(
- "could not find rlib for: `{}`, found rmeta (metadata) file",
- name
- ));
+ return Err(errors::LinkRlibError::OnlyRmetaFound { crate_name });
} else {
- return Err(format!("could not find rlib for: `{}`", name));
+ return Err(errors::LinkRlibError::NotFound { crate_name });
}
}
}
@@ -340,10 +362,7 @@ fn link_rlib<'a>(
// -whole-archive and it isn't clear how we can currently handle such a
// situation correctly.
// See https://github.com/rust-lang/rust/issues/88085#issuecomment-901050897
- sess.err(
- "the linking modifiers `+bundle` and `+whole-archive` are not compatible \
- with each other when generating rlibs",
- );
+ sess.emit_err(errors::IncompatibleLinkingModifiers);
}
NativeLibKind::Static { bundle: None | Some(true), .. } => {}
NativeLibKind::Static { bundle: Some(false), .. }
@@ -365,12 +384,8 @@ fn link_rlib<'a>(
));
continue;
}
- ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|e| {
- sess.fatal(&format!(
- "failed to add native library {}: {}",
- location.to_string_lossy(),
- e
- ));
+ ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|error| {
+ sess.emit_fatal(errors::AddNativeLibrary { library_path: location, error });
});
}
}
@@ -386,8 +401,8 @@ fn link_rlib<'a>(
true,
);
- ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|e| {
- sess.fatal(&format!("failed to add native library {}: {}", output_path.display(), e));
+ ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
+ sess.emit_fatal(errors::AddNativeLibrary { library_path: output_path, error });
});
}
@@ -452,14 +467,11 @@ fn collate_raw_dylibs<'a, 'b>(
// FIXME: when we add support for ordinals, figure out if we need to do anything
// if we have two DllImport values with the same name but different ordinals.
if import.calling_convention != old_import.calling_convention {
- sess.span_err(
- import.span,
- &format!(
- "multiple declarations of external function `{}` from \
- library `{}` have different calling conventions",
- import.name, name,
- ),
- );
+ sess.emit_err(errors::MultipleExternalFuncDecl {
+ span: import.span,
+ function: import.name,
+ library_name: &name,
+ });
}
}
}
@@ -502,7 +514,7 @@ fn link_staticlib<'a>(
)?;
let mut all_native_libs = vec![];
- let res = each_linked_rlib(&codegen_results.crate_info, &mut |cnum, path| {
+ let res = each_linked_rlib(sess, &codegen_results.crate_info, &mut |cnum, path| {
let name = codegen_results.crate_info.crate_name[&cnum];
let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
@@ -561,7 +573,7 @@ fn link_staticlib<'a>(
all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned());
});
if let Err(e) = res {
- sess.fatal(&e);
+ sess.emit_fatal(e);
}
ab.build(out_filename);
@@ -674,9 +686,7 @@ fn link_dwarf_object<'a>(
}) {
Ok(()) => {}
Err(e) => {
- sess.struct_err("linking dwarf objects with thorin failed")
- .note(&format!("{:?}", e))
- .emit();
+ sess.emit_err(errors::ThorinErrorWrapper(e));
sess.abort_if_errors();
}
}
@@ -749,8 +759,7 @@ fn link_natively<'a>(
// then it should not default to linking executables as pie. Different
// versions of gcc seem to use different quotes in the error message so
// don't check for them.
- if sess.target.linker_is_gnu
- && flavor != LinkerFlavor::Ld
+ if matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
&& unknown_arg_regex.is_match(&out)
&& out.contains("-no-pie")
&& cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie")
@@ -768,8 +777,7 @@ fn link_natively<'a>(
// Detect '-static-pie' used with an older version of gcc or clang not supporting it.
// Fallback from '-static-pie' to '-static' in that case.
- if sess.target.linker_is_gnu
- && flavor != LinkerFlavor::Ld
+ if matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
&& unknown_arg_regex.is_match(&out)
&& (out.contains("-static-pie") || out.contains("--no-dynamic-linker"))
&& cmd.get_args().iter().any(|e| e.to_string_lossy() == "-static-pie")
@@ -882,29 +890,20 @@ fn link_natively<'a>(
let mut output = prog.stderr.clone();
output.extend_from_slice(&prog.stdout);
let escaped_output = escape_string(&output);
- let mut err = sess.struct_err(&format!(
- "linking with `{}` failed: {}",
- linker_path.display(),
- prog.status
- ));
- err.note(&format!("{:?}", &cmd)).note(&escaped_output);
- if escaped_output.contains("undefined reference to") {
- err.help(
- "some `extern` functions couldn't be found; some native libraries may \
- need to be installed or have their path specified",
- );
- err.note("use the `-l` flag to specify native libraries to link");
- err.note("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)");
- }
- err.emit();
-
+ // FIXME: Add UI tests for this error.
+ let err = errors::LinkingFailed {
+ linker_path: &linker_path,
+ exit_status: prog.status,
+ command: &cmd,
+ escaped_output: &escaped_output,
+ };
+ sess.diagnostic().emit_err(err);
// If MSVC's `link.exe` was expected but the return code
// is not a Microsoft LNK error then suggest a way to fix or
// install the Visual Studio build tools.
if let Some(code) = prog.status.code() {
if sess.target.is_like_msvc
- && flavor == LinkerFlavor::Msvc
+ && flavor == LinkerFlavor::Msvc(Lld::No)
// Respect the command line override
&& sess.opts.cg.linker.is_none()
// Match exactly "link.exe"
@@ -980,9 +979,10 @@ fn link_natively<'a>(
but `link.exe` was not found",
);
sess.note_without_error(
- "please ensure that VS 2013, VS 2015, VS 2017, VS 2019 or VS 2022 \
- was installed with the Visual C++ option",
+ "please ensure that Visual Studio 2017 or later, or Build Tools \
+ for Visual Studio were installed with the Visual C++ option.",
);
+ sess.note_without_error("VS Code is a different product, and is not sufficient.");
}
sess.abort_if_errors();
}
@@ -1035,16 +1035,36 @@ fn link_natively<'a>(
if sess.target.is_like_osx {
match (strip, crate_type) {
- (Strip::Debuginfo, _) => strip_symbols_in_osx(sess, &out_filename, Some("-S")),
+ (Strip::Debuginfo, _) => {
+ strip_symbols_with_external_utility(sess, "strip", &out_filename, Some("-S"))
+ }
// Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
(Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => {
- strip_symbols_in_osx(sess, &out_filename, Some("-x"))
+ strip_symbols_with_external_utility(sess, "strip", &out_filename, Some("-x"))
+ }
+ (Strip::Symbols, _) => {
+ strip_symbols_with_external_utility(sess, "strip", &out_filename, None)
}
- (Strip::Symbols, _) => strip_symbols_in_osx(sess, &out_filename, None),
(Strip::None, _) => {}
}
}
+ if sess.target.os == "illumos" {
+ // Many illumos systems will have both the native 'strip' utility and
+ // the GNU one. Use the native version explicitly and do not rely on
+ // what's in the path.
+ let stripcmd = "/usr/bin/strip";
+ match strip {
+ // Always preserve the symbol table (-x).
+ Strip::Debuginfo => {
+ strip_symbols_with_external_utility(sess, stripcmd, &out_filename, Some("-x"))
+ }
+ // Strip::Symbols is handled via the --strip-all linker option.
+ Strip::Symbols => {}
+ Strip::None => {}
+ }
+ }
+
Ok(())
}
@@ -1056,8 +1076,13 @@ fn strip_value(sess: &Session) -> Strip {
}
}
-fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: Option<&str>) {
- let mut cmd = Command::new("strip");
+fn strip_symbols_with_external_utility<'a>(
+ sess: &'a Session,
+ util: &str,
+ out_filename: &Path,
+ option: Option<&str>,
+) {
+ let mut cmd = Command::new(util);
if let Some(option) = option {
cmd.arg(option);
}
@@ -1068,14 +1093,14 @@ fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: Opti
let mut output = prog.stderr.clone();
output.extend_from_slice(&prog.stdout);
sess.struct_warn(&format!(
- "stripping debug info with `strip` failed: {}",
- prog.status
+ "stripping debug info with `{}` failed: {}",
+ util, prog.status
))
.note(&escape_string(&output))
.emit();
}
}
- Err(e) => sess.fatal(&format!("unable to run `strip`: {}", e)),
+ Err(e) => sess.fatal(&format!("unable to run `{}`: {}", util, e)),
}
}
@@ -1091,11 +1116,12 @@ fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut d
// both executables and dynamic shared objects. Everywhere else the runtimes
// are currently distributed as static libraries which should be linked to
// executables only.
- let needs_runtime = match crate_type {
- CrateType::Executable => true,
- CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => sess.target.is_like_osx,
- CrateType::Rlib | CrateType::Staticlib => false,
- };
+ let needs_runtime = !sess.target.is_like_android
+ && match crate_type {
+ CrateType::Executable => true,
+ CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => sess.target.is_like_osx,
+ CrateType::Rlib | CrateType::Staticlib => false,
+ };
if !needs_runtime {
return;
@@ -1187,7 +1213,10 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
// only the linker flavor is known; use the default linker for the selected flavor
(None, Some(flavor)) => Some((
PathBuf::from(match flavor {
- LinkerFlavor::Gcc => {
+ LinkerFlavor::Gnu(Cc::Yes, _)
+ | LinkerFlavor::Darwin(Cc::Yes, _)
+ | LinkerFlavor::WasmLld(Cc::Yes)
+ | LinkerFlavor::Unix(Cc::Yes) => {
if cfg!(any(target_os = "solaris", target_os = "illumos")) {
// On historical Solaris systems, "cc" may have
// been Sun Studio, which is not flag-compatible
@@ -1200,9 +1229,14 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
"cc"
}
}
- LinkerFlavor::Ld => "ld",
- LinkerFlavor::Lld(_) => "lld",
- LinkerFlavor::Msvc => "link.exe",
+ LinkerFlavor::Gnu(_, Lld::Yes)
+ | LinkerFlavor::Darwin(_, Lld::Yes)
+ | LinkerFlavor::WasmLld(..)
+ | LinkerFlavor::Msvc(Lld::Yes) => "lld",
+ LinkerFlavor::Gnu(..) | LinkerFlavor::Darwin(..) | LinkerFlavor::Unix(..) => {
+ "ld"
+ }
+ LinkerFlavor::Msvc(..) => "link.exe",
LinkerFlavor::EmCc => {
if cfg!(windows) {
"emcc.bat"
@@ -1227,15 +1261,20 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|| stem == "clang"
|| stem.ends_with("-clang")
{
- LinkerFlavor::Gcc
+ LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target)
} else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
- LinkerFlavor::Lld(LldFlavor::Wasm)
- } else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
- LinkerFlavor::Ld
- } else if stem == "link" || stem == "lld-link" {
- LinkerFlavor::Msvc
+ LinkerFlavor::WasmLld(Cc::No)
+ } else if stem == "ld" || stem.ends_with("-ld") {
+ LinkerFlavor::from_cli(LinkerFlavorCli::Ld, &sess.target)
+ } else if stem == "ld.lld" {
+ LinkerFlavor::Gnu(Cc::No, Lld::Yes)
+ } else if stem == "link" {
+ LinkerFlavor::Msvc(Lld::No)
+ } else if stem == "lld-link" {
+ LinkerFlavor::Msvc(Lld::Yes)
} else if stem == "lld" || stem == "rust-lld" {
- LinkerFlavor::Lld(sess.target.lld_flavor)
+ let lld_flavor = sess.target.linker_flavor.lld_flavor();
+ LinkerFlavor::from_cli(LinkerFlavorCli::Lld(lld_flavor), &sess.target)
} else {
// fall back to the value in the target spec
sess.target.linker_flavor
@@ -1249,7 +1288,8 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
// linker and linker flavor specified via command line have precedence over what the target
// specification specifies
- let linker_flavor = sess.opts.cg.linker_flavor.map(LinkerFlavor::from_cli);
+ let linker_flavor =
+ sess.opts.cg.linker_flavor.map(|flavor| LinkerFlavor::from_cli(flavor, &sess.target));
if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor) {
return ret;
}
@@ -1320,7 +1360,7 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
let verbatim = lib.verbatim.unwrap_or(false);
if sess.target.is_like_msvc {
Some(format!("{}{}", name, if verbatim { "" } else { ".lib" }))
- } else if sess.target.linker_is_gnu {
+ } else if sess.target.linker_flavor.is_gnu() {
Some(format!("-l{}{}", if verbatim { ":" } else { "" }, name))
} else {
Some(format!("-l{}", name))
@@ -1607,7 +1647,7 @@ fn add_pre_link_objects(
let empty = Default::default();
let objects = if self_contained {
&opts.pre_link_objects_self_contained
- } else if !(sess.target.os == "fuchsia" && flavor == LinkerFlavor::Gcc) {
+ } else if !(sess.target.os == "fuchsia" && matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))) {
&opts.pre_link_objects
} else {
&empty
@@ -1647,7 +1687,7 @@ fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor)
fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_type: CrateType) {
match (crate_type, &sess.target.link_script) {
(CrateType::Cdylib | CrateType::Executable, Some(script)) => {
- if !sess.target.linker_is_gnu {
+ if !sess.target.linker_flavor.is_gnu() {
sess.fatal("can only use link script when linking with GNU-like linker");
}
@@ -1890,7 +1930,7 @@ fn add_rpath_args(
out_filename: out_filename.to_path_buf(),
has_rpath: sess.target.has_rpath,
is_like_osx: sess.target.is_like_osx,
- linker_is_gnu: sess.target.linker_is_gnu,
+ linker_is_gnu: sess.target.linker_flavor.is_gnu(),
};
cmd.args(&rpath::get_rpath_flags(&mut rpath_config));
}
@@ -2134,7 +2174,7 @@ fn add_order_independent_options(
if sess.target.os == "fuchsia"
&& crate_type == CrateType::Executable
- && flavor != LinkerFlavor::Gcc
+ && !matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
{
let prefix = if sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
"asan/"
@@ -2747,12 +2787,12 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
let llvm_target = &sess.target.llvm_target;
if sess.target.vendor != "apple"
|| !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "macos")
- || (flavor != LinkerFlavor::Gcc && flavor != LinkerFlavor::Lld(LldFlavor::Ld64))
+ || !matches!(flavor, LinkerFlavor::Darwin(..))
{
return;
}
- if os == "macos" && flavor != LinkerFlavor::Lld(LldFlavor::Ld64) {
+ if os == "macos" && !matches!(flavor, LinkerFlavor::Darwin(Cc::No, _)) {
return;
}
@@ -2786,10 +2826,10 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
};
match flavor {
- LinkerFlavor::Gcc => {
+ LinkerFlavor::Darwin(Cc::Yes, _) => {
cmd.args(&["-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]);
}
- LinkerFlavor::Lld(LldFlavor::Ld64) => {
+ LinkerFlavor::Darwin(Cc::No, _) => {
cmd.args(&["-syslibroot", &sdk_root]);
}
_ => unreachable!(),
@@ -2852,7 +2892,10 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> {
fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
if let Some(ld_impl) = sess.opts.unstable_opts.gcc_ld {
- if let LinkerFlavor::Gcc = flavor {
+ if let LinkerFlavor::Gnu(Cc::Yes, _)
+ | LinkerFlavor::Darwin(Cc::Yes, _)
+ | LinkerFlavor::WasmLld(Cc::Yes) = flavor
+ {
match ld_impl {
LdImpl::Lld => {
// Implement the "self-contained" part of -Zgcc-ld
@@ -2867,7 +2910,7 @@ fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
// Implement the "linker flavor" part of -Zgcc-ld
// by asking cc to use some kind of lld.
cmd.arg("-fuse-ld=lld");
- if sess.target.lld_flavor != LldFlavor::Ld {
+ if !flavor.is_gnu() {
// Tell clang to use a non-default LLD flavor.
// Gcc doesn't understand the target option, but we currently assume
// that gcc is not used for Apple and Wasm targets (#97402).
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index e505543b2..c49b19bdf 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -1,5 +1,6 @@
use super::command::Command;
use super::symbol_export;
+use crate::errors;
use rustc_span::symbol::sym;
use std::ffi::{OsStr, OsString};
@@ -16,7 +17,7 @@ use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, S
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
use rustc_session::Session;
-use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
+use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld};
use cc::windows_registry;
@@ -56,8 +57,13 @@ pub fn get_linker<'a>(
let mut cmd = match linker.to_str() {
Some(linker) if cfg!(windows) && linker.ends_with(".bat") => Command::bat_script(linker),
_ => match flavor {
- LinkerFlavor::Lld(f) => Command::lld(linker, f),
- LinkerFlavor::Msvc if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() => {
+ LinkerFlavor::Gnu(Cc::No, Lld::Yes)
+ | LinkerFlavor::Darwin(Cc::No, Lld::Yes)
+ | LinkerFlavor::WasmLld(Cc::No)
+ | LinkerFlavor::Msvc(Lld::Yes) => Command::lld(linker, flavor.lld_flavor()),
+ LinkerFlavor::Msvc(Lld::No)
+ if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() =>
+ {
Command::new(msvc_tool.as_ref().map_or(linker, |t| t.path()))
}
_ => Command::new(linker),
@@ -68,9 +74,7 @@ pub fn get_linker<'a>(
// To comply with the Windows App Certification Kit,
// MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc).
let t = &sess.target;
- if (flavor == LinkerFlavor::Msvc || flavor == LinkerFlavor::Lld(LldFlavor::Link))
- && t.vendor == "uwp"
- {
+ if matches!(flavor, LinkerFlavor::Msvc(..)) && t.vendor == "uwp" {
if let Some(ref tool) = msvc_tool {
let original_path = tool.path();
if let Some(ref root_lib_path) = original_path.ancestors().nth(4) {
@@ -126,23 +130,22 @@ pub fn get_linker<'a>(
// to the linker args construction.
assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp");
match flavor {
- LinkerFlavor::Gcc => {
- Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: false })
- as Box<dyn Linker>
- }
- LinkerFlavor::Ld if sess.target.os == "l4re" => {
+ LinkerFlavor::Unix(Cc::No) if sess.target.os == "l4re" => {
Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>
}
- LinkerFlavor::Lld(LldFlavor::Ld)
- | LinkerFlavor::Lld(LldFlavor::Ld64)
- | LinkerFlavor::Ld => {
- Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: true })
- as Box<dyn Linker>
- }
- LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => {
- Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>
- }
- LinkerFlavor::Lld(LldFlavor::Wasm) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>,
+ LinkerFlavor::WasmLld(Cc::No) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>,
+ LinkerFlavor::Gnu(cc, _)
+ | LinkerFlavor::Darwin(cc, _)
+ | LinkerFlavor::WasmLld(cc)
+ | LinkerFlavor::Unix(cc) => Box::new(GccLinker {
+ cmd,
+ sess,
+ target_cpu,
+ hinted_static: false,
+ is_ld: cc == Cc::No,
+ is_gnu: flavor.is_gnu(),
+ }) as Box<dyn Linker>,
+ LinkerFlavor::Msvc(..) => Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>,
LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>,
LinkerFlavor::Bpf => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>,
LinkerFlavor::Ptx => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
@@ -211,6 +214,7 @@ pub struct GccLinker<'a> {
hinted_static: bool, // Keeps track of the current hinting mode.
// Link as ld
is_ld: bool,
+ is_gnu: bool,
}
impl<'a> GccLinker<'a> {
@@ -359,7 +363,7 @@ impl<'a> Linker for GccLinker<'a> {
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
match output_kind {
LinkOutputKind::DynamicNoPicExe => {
- if !self.is_ld && self.sess.target.linker_is_gnu {
+ if !self.is_ld && self.is_gnu {
self.cmd.arg("-no-pie");
}
}
@@ -373,7 +377,7 @@ impl<'a> Linker for GccLinker<'a> {
LinkOutputKind::StaticNoPicExe => {
// `-static` works for both gcc wrapper and ld.
self.cmd.arg("-static");
- if !self.is_ld && self.sess.target.linker_is_gnu {
+ if !self.is_ld && self.is_gnu {
self.cmd.arg("-no-pie");
}
}
@@ -431,26 +435,26 @@ impl<'a> Linker for GccLinker<'a> {
// FIXME(81490): ld64 doesn't support these flags but macOS 11
// has -needed-l{} / -needed_library {}
// but we have no way to detect that here.
- self.sess.warn("`as-needed` modifier not implemented yet for ld64");
- } else if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows {
+ self.sess.emit_warning(errors::Ld64UnimplementedModifier);
+ } else if self.is_gnu && !self.sess.target.is_like_windows {
self.linker_arg("--no-as-needed");
} else {
- self.sess.warn("`as-needed` modifier not supported for current linker");
+ self.sess.emit_warning(errors::LinkerUnsupportedModifier);
}
}
self.hint_dynamic();
- self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib));
+ self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },));
if !as_needed {
if self.sess.target.is_like_osx {
// See above FIXME comment
- } else if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows {
+ } else if self.is_gnu && !self.sess.target.is_like_windows {
self.linker_arg("--as-needed");
}
}
}
fn link_staticlib(&mut self, lib: &str, verbatim: bool) {
self.hint_static();
- self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib));
+ self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },));
}
fn link_rlib(&mut self, lib: &Path) {
self.hint_static();
@@ -489,7 +493,7 @@ impl<'a> Linker for GccLinker<'a> {
// FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
// flag but we have no way to detect that here.
// self.cmd.arg("-needed_framework").arg(framework);
- self.sess.warn("`as-needed` modifier not implemented yet for ld64");
+ self.sess.emit_warning(errors::Ld64UnimplementedModifier);
}
self.cmd.arg("-framework").arg(framework);
}
@@ -504,11 +508,8 @@ impl<'a> Linker for GccLinker<'a> {
self.hint_static();
let target = &self.sess.target;
if !target.is_like_osx {
- self.linker_arg("--whole-archive").cmd.arg(format!(
- "-l{}{}",
- if verbatim { ":" } else { "" },
- lib
- ));
+ self.linker_arg("--whole-archive");
+ self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },));
self.linker_arg("--no-whole-archive");
} else {
// -force_load is the macOS equivalent of --whole-archive, but it
@@ -553,21 +554,19 @@ impl<'a> Linker for GccLinker<'a> {
// eliminate the metadata. If we're building an executable, however,
// --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
// reduction.
- } else if (self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm)
- && !keep_metadata
- {
+ } else if (self.is_gnu || self.sess.target.is_like_wasm) && !keep_metadata {
self.linker_arg("--gc-sections");
}
}
fn no_gc_sections(&mut self) {
- if self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm {
+ if self.is_gnu || self.sess.target.is_like_wasm {
self.linker_arg("--no-gc-sections");
}
}
fn optimize(&mut self) {
- if !self.sess.target.linker_is_gnu && !self.sess.target.is_like_wasm {
+ if !self.is_gnu && !self.sess.target.is_like_wasm {
return;
}
@@ -581,7 +580,7 @@ impl<'a> Linker for GccLinker<'a> {
}
fn pgo_gen(&mut self) {
- if !self.sess.target.linker_is_gnu {
+ if !self.is_gnu {
return;
}
@@ -611,7 +610,13 @@ impl<'a> Linker for GccLinker<'a> {
match strip {
Strip::None => {}
Strip::Debuginfo => {
- self.linker_arg("--strip-debug");
+ // The illumos linker does not support --strip-debug although
+ // it does support --strip-all as a compatibility alias for -s.
+ // The --strip-debug case is handled by running an external
+ // `strip` utility as a separate step after linking.
+ if self.sess.target.os != "illumos" {
+ self.linker_arg("--strip-debug");
+ }
}
Strip::Symbols => {
self.linker_arg("--strip-all");
@@ -667,8 +672,8 @@ impl<'a> Linker for GccLinker<'a> {
writeln!(f, "_{}", sym)?;
}
};
- if let Err(e) = res {
- self.sess.fatal(&format!("failed to write lib.def file: {}", e));
+ if let Err(error) = res {
+ self.sess.emit_fatal(errors::LibDefWriteFailure { error });
}
} else if is_windows {
let res: io::Result<()> = try {
@@ -682,8 +687,8 @@ impl<'a> Linker for GccLinker<'a> {
writeln!(f, " {}", symbol)?;
}
};
- if let Err(e) = res {
- self.sess.fatal(&format!("failed to write list.def file: {}", e));
+ if let Err(error) = res {
+ self.sess.emit_fatal(errors::LibDefWriteFailure { error });
}
} else {
// Write an LD version script
@@ -699,8 +704,8 @@ impl<'a> Linker for GccLinker<'a> {
}
writeln!(f, "\n local:\n *;\n}};")?;
};
- if let Err(e) = res {
- self.sess.fatal(&format!("failed to write version script: {}", e));
+ if let Err(error) = res {
+ self.sess.emit_fatal(errors::VersionScriptWriteFailure { error });
}
}
@@ -752,13 +757,13 @@ impl<'a> Linker for GccLinker<'a> {
fn add_no_exec(&mut self) {
if self.sess.target.is_like_windows {
self.linker_arg("--nxcompat");
- } else if self.sess.target.linker_is_gnu {
+ } else if self.is_gnu {
self.linker_arg("-znoexecstack");
}
}
fn add_as_needed(&mut self) {
- if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows {
+ if self.is_gnu && !self.sess.target.is_like_windows {
self.linker_arg("--as-needed");
} else if self.sess.target.is_like_solaris {
// -z ignore is the Solaris equivalent to the GNU ld --as-needed option
@@ -917,9 +922,8 @@ impl<'a> Linker for MsvcLinker<'a> {
self.cmd.arg(arg);
}
}
- Err(err) => {
- self.sess
- .warn(&format!("error enumerating natvis directory: {}", err));
+ Err(error) => {
+ self.sess.emit_warning(errors::NoNatvisDirectory { error });
}
}
}
@@ -973,8 +977,8 @@ impl<'a> Linker for MsvcLinker<'a> {
writeln!(f, " {}", symbol)?;
}
};
- if let Err(e) = res {
- self.sess.fatal(&format!("failed to write lib.def file: {}", e));
+ if let Err(error) = res {
+ self.sess.emit_fatal(errors::LibDefWriteFailure { error });
}
let mut arg = OsString::from("/DEF:");
arg.push(path);
@@ -1174,22 +1178,19 @@ impl<'a> WasmLd<'a> {
// sharing memory and instantiating the module multiple times. As a
// result if it were exported then we'd just have no sharing.
//
- // * `--export=__wasm_init_memory` - when using `--passive-segments` the
- // linker will synthesize this function, and so we need to make sure
- // that our usage of `--export` below won't accidentally cause this
- // function to get deleted.
- //
- // * `--export=*tls*` - when `#[thread_local]` symbols are used these
- // symbols are how the TLS segments are initialized and configured.
+ // On wasm32-unknown-unknown, we also export symbols for glue code to use:
+ // * `--export=*tls*` - when `#[thread_local]` symbols are used these
+ // symbols are how the TLS segments are initialized and configured.
if sess.target_features.contains(&sym::atomics) {
cmd.arg("--shared-memory");
cmd.arg("--max-memory=1073741824");
cmd.arg("--import-memory");
- cmd.arg("--export=__wasm_init_memory");
- cmd.arg("--export=__wasm_init_tls");
- cmd.arg("--export=__tls_size");
- cmd.arg("--export=__tls_align");
- cmd.arg("--export=__tls_base");
+ if sess.target.os == "unknown" {
+ cmd.arg("--export=__wasm_init_tls");
+ cmd.arg("--export=__tls_size");
+ cmd.arg("--export=__tls_align");
+ cmd.arg("--export=__tls_base");
+ }
}
WasmLd { cmd, sess }
}
@@ -1314,10 +1315,12 @@ impl<'a> Linker for WasmLd<'a> {
// LLD will hide these otherwise-internal symbols since it only exports
// symbols explicitly passed via the `--export` flags above and hides all
- // others. Various bits and pieces of tooling use this, so be sure these
- // symbols make their way out of the linker as well.
- self.cmd.arg("--export=__heap_base");
- self.cmd.arg("--export=__data_end");
+ // others. Various bits and pieces of wasm32-unknown-unknown tooling use
+ // this, so be sure these symbols make their way out of the linker as well.
+ if self.sess.target.os == "unknown" {
+ self.cmd.arg("--export=__heap_base");
+ self.cmd.arg("--export=__data_end");
+ }
}
fn subsystem(&mut self, _subsystem: &str) {}
@@ -1438,7 +1441,7 @@ impl<'a> Linker for L4Bender<'a> {
fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
// ToDo, not implemented, copy from GCC
- self.sess.warn("exporting symbols not implemented yet for L4Bender");
+ self.sess.emit_warning(errors::L4BenderExportingSymbolsUnimplemented);
return;
}
@@ -1730,8 +1733,8 @@ impl<'a> Linker for BpfLinker<'a> {
writeln!(f, "{}", sym)?;
}
};
- if let Err(e) = res {
- self.sess.fatal(&format!("failed to write symbols file: {}", e));
+ if let Err(error) = res {
+ self.sess.emit_fatal(errors::SymbolFileWriteFailure { error });
} else {
self.cmd.arg("--export-symbols").arg(&path);
}
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 8d7e2c5cf..c2ecc4160 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -13,7 +13,7 @@ use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::Instance;
use rustc_middle::ty::{self, SymbolName, TyCtxt};
-use rustc_session::config::CrateType;
+use rustc_session::config::{CrateType, OomStrategy};
use rustc_target::spec::SanitizerSet;
pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
@@ -76,7 +76,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
// let it through if it's included statically.
match tcx.hir().get_by_def_id(def_id) {
Node::ForeignItem(..) => {
- tcx.is_statically_included_foreign_item(def_id).then_some(def_id)
+ tcx.native_library(def_id).map_or(false, |library| library.kind.is_statically_included()).then_some(def_id)
}
// Only consider nodes that actually have exported symbols.
@@ -206,6 +206,15 @@ fn exported_symbols_provider_local<'tcx>(
},
));
}
+
+ symbols.push((
+ ExportedSymbol::NoDefId(SymbolName::new(tcx, OomStrategy::SYMBOL)),
+ SymbolExportInfo {
+ level: SymbolExportLevel::Rust,
+ kind: SymbolExportKind::Text,
+ used: false,
+ },
+ ));
}
if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() {
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 68f3b19b7..d0ac016b0 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -2,11 +2,11 @@ use super::link::{self, ensure_removed};
use super::lto::{self, SerializedModule};
use super::symbol_export::symbol_name_for_instance_in_crate;
+use crate::errors;
+use crate::traits::*;
use crate::{
CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
};
-
-use crate::traits::*;
use jobserver::{Acquired, Client};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::memmap::Mmap;
@@ -15,7 +15,10 @@ use rustc_data_structures::profiling::TimingGuard;
use rustc_data_structures::profiling::VerboseTimingGuard;
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::Emitter;
-use rustc_errors::{translation::Translate, DiagnosticId, FatalError, Handler, Level};
+use rustc_errors::{
+ translation::{to_fluent_args, Translate},
+ DiagnosticId, FatalError, Handler, Level,
+};
use rustc_fs_util::link_or_copy;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_incremental::{
@@ -113,7 +116,6 @@ pub struct ModuleConfig {
pub vectorize_slp: bool,
pub merge_functions: bool,
pub inline_threshold: Option<u32>,
- pub new_llvm_pass_manager: Option<bool>,
pub emit_lifetime_markers: bool,
pub llvm_plugins: Vec<String>,
}
@@ -265,7 +267,6 @@ impl ModuleConfig {
},
inline_threshold: sess.opts.cg.inline_threshold,
- new_llvm_pass_manager: sess.opts.unstable_opts.new_llvm_pass_manager,
emit_lifetime_markers: sess.emit_lifetime_markers(),
llvm_plugins: if_regular!(sess.opts.unstable_opts.llvm_plugins.clone(), vec![]),
}
@@ -532,7 +533,7 @@ fn produce_final_output_artifacts(
// Produce final compile outputs.
let copy_gracefully = |from: &Path, to: &Path| {
if let Err(e) = fs::copy(from, to) {
- sess.err(&format!("could not copy {:?} to {:?}: {}", from, to, e));
+ sess.emit_err(errors::CopyPath::new(from, to, e));
}
};
@@ -548,7 +549,7 @@ fn produce_final_output_artifacts(
ensure_removed(sess.diagnostic(), &path);
}
} else {
- let ext = crate_output
+ let extension = crate_output
.temp_path(output_type, None)
.extension()
.unwrap()
@@ -559,19 +560,11 @@ fn produce_final_output_artifacts(
if crate_output.outputs.contains_key(&output_type) {
// 2) Multiple codegen units, with `--emit foo=some_name`. We have
// no good solution for this case, so warn the user.
- sess.warn(&format!(
- "ignoring emit path because multiple .{} files \
- were produced",
- ext
- ));
+ sess.emit_warning(errors::IgnoringEmitPath { extension });
} else if crate_output.single_output_file.is_some() {
// 3) Multiple codegen units, with `-o some_name`. We have
// no good solution for this case, so warn the user.
- sess.warn(&format!(
- "ignoring -o because multiple .{} files \
- were produced",
- ext
- ));
+ sess.emit_warning(errors::IgnoringOutput { extension });
} else {
// 4) Multiple codegen units, but no explicit name. We
// just leave the `foo.0.x` files in place.
@@ -882,14 +875,12 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
);
match link_or_copy(&source_file, &output_path) {
Ok(_) => Some(output_path),
- Err(err) => {
- let diag_handler = cgcx.create_diag_handler();
- diag_handler.err(&format!(
- "unable to copy {} to {}: {}",
- source_file.display(),
- output_path.display(),
- err
- ));
+ Err(error) => {
+ cgcx.create_diag_handler().emit_err(errors::CopyPathBuf {
+ source_file,
+ output_path,
+ error,
+ });
None
}
}
@@ -1008,6 +999,14 @@ fn start_executing_work<B: ExtraBackendMethods>(
let coordinator_send = tx_to_llvm_workers;
let sess = tcx.sess;
+ let mut each_linked_rlib_for_lto = Vec::new();
+ drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| {
+ if link::ignored_for_lto(sess, crate_info, cnum) {
+ return;
+ }
+ each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
+ }));
+
// Compute the set of symbols we need to retain when doing LTO (if we need to)
let exported_symbols = {
let mut exported_symbols = FxHashMap::default();
@@ -1029,7 +1028,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
}
Lto::Fat | Lto::Thin => {
exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE));
- for &cnum in tcx.crates(()).iter() {
+ for &(cnum, ref _path) in &each_linked_rlib_for_lto {
exported_symbols.insert(cnum, copy_symbols(cnum));
}
Some(Arc::new(exported_symbols))
@@ -1049,14 +1048,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
})
.expect("failed to spawn helper thread");
- let mut each_linked_rlib_for_lto = Vec::new();
- drop(link::each_linked_rlib(crate_info, &mut |cnum, path| {
- if link::ignored_for_lto(sess, crate_info, cnum) {
- return;
- }
- each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
- }));
-
let ol =
if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() {
// If we know that we won’t be doing codegen, create target machines without optimisation.
@@ -1639,7 +1630,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
llvm_start_time: &mut Option<VerboseTimingGuard<'a>>,
) {
if config.time_module && llvm_start_time.is_none() {
- *llvm_start_time = Some(prof.extra_verbose_generic_activity("LLVM_passes", "crate"));
+ *llvm_start_time = Some(prof.verbose_generic_activity("LLVM_passes"));
}
}
}
@@ -1752,7 +1743,7 @@ impl Translate for SharedEmitter {
impl Emitter for SharedEmitter {
fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
- let fluent_args = self.to_fluent_args(diag.args());
+ let fluent_args = to_fluent_args(diag.args());
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
msg: self.translate_messages(&diag.message, &fluent_args).to_string(),
code: diag.code.clone(),
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index b98ff4957..84b89cd71 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -39,7 +39,7 @@ use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::Symbol;
use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
-use rustc_target::abi::{Align, VariantIdx};
+use rustc_target::abi::{Align, Size, VariantIdx};
use std::collections::BTreeSet;
use std::convert::TryFrom;
@@ -151,7 +151,12 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
(&ty::Array(_, len), &ty::Slice(_)) => {
cx.const_usize(len.eval_usize(cx.tcx(), ty::ParamEnv::reveal_all()))
}
- (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
+ (
+ &ty::Dynamic(ref data_a, _, src_dyn_kind),
+ &ty::Dynamic(ref data_b, _, target_dyn_kind),
+ ) => {
+ assert_eq!(src_dyn_kind, target_dyn_kind);
+
let old_info =
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
if data_a.principal_def_id() == data_b.principal_def_id() {
@@ -167,11 +172,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
if let Some(entry_idx) = vptr_entry_idx {
let ptr_ty = cx.type_i8p();
let ptr_align = cx.tcx().data_layout.pointer_align.abi;
- let vtable_ptr_ty = cx.scalar_pair_element_backend_type(
- cx.layout_of(cx.tcx().mk_mut_ptr(target)),
- 1,
- true,
- );
+ let vtable_ptr_ty = vtable_ptr_ty(cx, target, target_dyn_kind);
let llvtable = bx.pointercast(old_info, bx.type_ptr_to(ptr_ty));
let gep = bx.inbounds_gep(
ptr_ty,
@@ -187,18 +188,32 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
old_info
}
}
- (_, &ty::Dynamic(ref data, ..)) => {
- let vtable_ptr_ty = cx.scalar_pair_element_backend_type(
- cx.layout_of(cx.tcx().mk_mut_ptr(target)),
- 1,
- true,
- );
+ (_, &ty::Dynamic(ref data, _, target_dyn_kind)) => {
+ let vtable_ptr_ty = vtable_ptr_ty(cx, target, target_dyn_kind);
cx.const_ptrcast(meth::get_vtable(cx, source, data.principal()), vtable_ptr_ty)
}
_ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
}
}
+// Returns the vtable pointer type of a `dyn` or `dyn*` type
+fn vtable_ptr_ty<'tcx, Cx: CodegenMethods<'tcx>>(
+ cx: &Cx,
+ target: Ty<'tcx>,
+ kind: ty::DynKind,
+) -> <Cx as BackendTypes>::Type {
+ cx.scalar_pair_element_backend_type(
+ cx.layout_of(match kind {
+ // vtable is the second field of `*mut dyn Trait`
+ ty::Dyn => cx.tcx().mk_mut_ptr(target),
+ // vtable is the second field of `dyn* Trait`
+ ty::DynStar => target,
+ }),
+ 1,
+ true,
+ )
+}
+
/// Coerces `src` to `dst_ty`. `src_ty` must be a pointer.
pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
@@ -248,6 +263,29 @@ pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
}
}
+/// Coerces `src` to `dst_ty` which is guaranteed to be a `dyn*` type.
+pub fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+ bx: &mut Bx,
+ src: Bx::Value,
+ src_ty_and_layout: TyAndLayout<'tcx>,
+ dst_ty: Ty<'tcx>,
+ old_info: Option<Bx::Value>,
+) -> (Bx::Value, Bx::Value) {
+ debug!("cast_to_dyn_star: {:?} => {:?}", src_ty_and_layout.ty, dst_ty);
+ assert!(
+ matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
+ "destination type must be a dyn*"
+ );
+ // FIXME(dyn-star): this is probably not the best way to check if this is
+ // a pointer, and really we should ensure that the value is a suitable
+ // pointer earlier in the compilation process.
+ let src = match src_ty_and_layout.pointee_info_at(bx.cx(), Size::ZERO) {
+ Some(_) => bx.ptrtoint(src, bx.cx().type_isize()),
+ None => bx.bitcast(src, bx.type_isize()),
+ };
+ (src, unsized_info(bx, src_ty_and_layout.ty, dst_ty, old_info))
+}
+
/// Coerces `src`, which is a reference to a value of type `src_ty`,
/// to a value of type `dst_ty`, and stores the result in `dst`.
pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
@@ -299,40 +337,26 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
- op: hir::BinOpKind,
- lhs: Bx::Value,
- rhs: Bx::Value,
-) -> Bx::Value {
- cast_shift_rhs(bx, op, lhs, rhs)
-}
-
-fn cast_shift_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
- bx: &mut Bx,
- op: hir::BinOpKind,
lhs: Bx::Value,
rhs: Bx::Value,
) -> Bx::Value {
// Shifts may have any size int on the rhs
- if op.is_shift() {
- let mut rhs_llty = bx.cx().val_ty(rhs);
- let mut lhs_llty = bx.cx().val_ty(lhs);
- if bx.cx().type_kind(rhs_llty) == TypeKind::Vector {
- rhs_llty = bx.cx().element_type(rhs_llty)
- }
- if bx.cx().type_kind(lhs_llty) == TypeKind::Vector {
- lhs_llty = bx.cx().element_type(lhs_llty)
- }
- let rhs_sz = bx.cx().int_width(rhs_llty);
- let lhs_sz = bx.cx().int_width(lhs_llty);
- if lhs_sz < rhs_sz {
- bx.trunc(rhs, lhs_llty)
- } else if lhs_sz > rhs_sz {
- // FIXME (#1877: If in the future shifting by negative
- // values is no longer undefined then this is wrong.
- bx.zext(rhs, lhs_llty)
- } else {
- rhs
- }
+ let mut rhs_llty = bx.cx().val_ty(rhs);
+ let mut lhs_llty = bx.cx().val_ty(lhs);
+ if bx.cx().type_kind(rhs_llty) == TypeKind::Vector {
+ rhs_llty = bx.cx().element_type(rhs_llty)
+ }
+ if bx.cx().type_kind(lhs_llty) == TypeKind::Vector {
+ lhs_llty = bx.cx().element_type(lhs_llty)
+ }
+ let rhs_sz = bx.cx().int_width(rhs_llty);
+ let lhs_sz = bx.cx().int_width(lhs_llty);
+ if lhs_sz < rhs_sz {
+ bx.trunc(rhs, lhs_llty)
+ } else if lhs_sz > rhs_sz {
+ // FIXME (#1877: If in the future shifting by negative
+ // values is no longer undefined then this is wrong.
+ bx.zext(rhs, lhs_llty)
} else {
rhs
}
@@ -475,7 +499,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, start_fn, &args, None);
+ let result = bx.call(start_ty, None, start_fn, &args, None);
let cast = bx.intcast(result, cx.type_int(), true);
bx.ret(cast);
diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs
index 8ca1a6084..71f9179d0 100644
--- a/compiler/rustc_codegen_ssa/src/common.rs
+++ b/compiler/rustc_codegen_ssa/src/common.rs
@@ -1,7 +1,6 @@
#![allow(non_camel_case_types)]
use rustc_errors::struct_span_err;
-use rustc_hir as hir;
use rustc_hir::LangItem;
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
@@ -140,7 +139,7 @@ pub fn build_unchecked_lshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
lhs: Bx::Value,
rhs: Bx::Value,
) -> Bx::Value {
- let rhs = base::cast_shift_expr_rhs(bx, hir::BinOpKind::Shl, lhs, rhs);
+ let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
// #1877, #10183: Ensure that input is always valid
let rhs = shift_mask_rhs(bx, rhs);
bx.shl(lhs, rhs)
@@ -152,7 +151,7 @@ pub fn build_unchecked_rshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
lhs: Bx::Value,
rhs: Bx::Value,
) -> Bx::Value {
- let rhs = base::cast_shift_expr_rhs(bx, hir::BinOpKind::Shr, lhs, rhs);
+ let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
// #1877, #10183: Ensure that input is always valid
let rhs = shift_mask_rhs(bx, rhs);
let is_signed = lhs_t.is_signed();
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 135ed680d..e05646e1e 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -666,10 +666,8 @@ 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)
});
- // Note: Don't use `StableHashResult` impl of `u64` here directly, since that
- // would lead to endianness problems.
- let hash: u128 = hasher.finish();
- (hash.to_le() as u64).to_le()
+ let hash: u64 = hasher.finish();
+ hash
});
if cpp_like_debuginfo(tcx) {
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
new file mode 100644
index 000000000..ebb531f1c
--- /dev/null
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -0,0 +1,356 @@
+//! Errors emitted by codegen_ssa
+
+use crate::back::command::Command;
+use rustc_errors::{
+ fluent, DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
+ IntoDiagnosticArg,
+};
+use rustc_macros::Diagnostic;
+use rustc_span::{Span, Symbol};
+use std::borrow::Cow;
+use std::io::Error;
+use std::path::{Path, PathBuf};
+use std::process::ExitStatus;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_lib_def_write_failure)]
+pub struct LibDefWriteFailure {
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_version_script_write_failure)]
+pub struct VersionScriptWriteFailure {
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_symbol_file_write_failure)]
+pub struct SymbolFileWriteFailure {
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_ld64_unimplemented_modifier)]
+pub struct Ld64UnimplementedModifier;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_linker_unsupported_modifier)]
+pub struct LinkerUnsupportedModifier;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_L4Bender_exporting_symbols_unimplemented)]
+pub struct L4BenderExportingSymbolsUnimplemented;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_no_natvis_directory)]
+pub struct NoNatvisDirectory {
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_copy_path_buf)]
+pub struct CopyPathBuf {
+ pub source_file: PathBuf,
+ pub output_path: PathBuf,
+ pub error: Error,
+}
+
+// Reports Paths using `Debug` implementation rather than Path's `Display` implementation.
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_copy_path)]
+pub struct CopyPath<'a> {
+ from: DebugArgPath<'a>,
+ to: DebugArgPath<'a>,
+ error: Error,
+}
+
+impl<'a> CopyPath<'a> {
+ pub fn new(from: &'a Path, to: &'a Path, error: Error) -> CopyPath<'a> {
+ CopyPath { from: DebugArgPath(from), to: DebugArgPath(to), error }
+ }
+}
+
+struct DebugArgPath<'a>(pub &'a Path);
+
+impl IntoDiagnosticArg for DebugArgPath<'_> {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self.0)))
+ }
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_ignoring_emit_path)]
+pub struct IgnoringEmitPath {
+ pub extension: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_ignoring_output)]
+pub struct IgnoringOutput {
+ pub extension: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_create_temp_dir)]
+pub struct CreateTempDir {
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_incompatible_linking_modifiers)]
+pub struct IncompatibleLinkingModifiers;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_add_native_library)]
+pub struct AddNativeLibrary {
+ pub library_path: PathBuf,
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_multiple_external_func_decl)]
+pub struct MultipleExternalFuncDecl<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub function: Symbol,
+ pub library_name: &'a str,
+}
+
+#[derive(Diagnostic)]
+pub enum LinkRlibError {
+ #[diag(codegen_ssa_rlib_missing_format)]
+ MissingFormat,
+
+ #[diag(codegen_ssa_rlib_only_rmeta_found)]
+ OnlyRmetaFound { crate_name: Symbol },
+
+ #[diag(codegen_ssa_rlib_not_found)]
+ NotFound { crate_name: Symbol },
+
+ #[diag(codegen_ssa_rlib_incompatible_dependency_formats)]
+ IncompatibleDependencyFormats { ty1: String, ty2: String, list1: String, list2: String },
+}
+
+pub struct ThorinErrorWrapper(pub thorin::Error);
+
+impl IntoDiagnostic<'_> for ThorinErrorWrapper {
+ fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+ let mut diag;
+ match self.0 {
+ thorin::Error::ReadInput(_) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_read_input_failure);
+ diag
+ }
+ thorin::Error::ParseFileKind(_) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_input_file_kind);
+ diag
+ }
+ thorin::Error::ParseObjectFile(_) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_input_object_file);
+ diag
+ }
+ thorin::Error::ParseArchiveFile(_) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_input_archive_file);
+ diag
+ }
+ thorin::Error::ParseArchiveMember(_) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_archive_member);
+ diag
+ }
+ thorin::Error::InvalidInputKind => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_invalid_input_kind);
+ diag
+ }
+ thorin::Error::DecompressData(_) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_decompress_data);
+ diag
+ }
+ thorin::Error::NamelessSection(_, offset) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_section_without_name);
+ diag.set_arg("offset", format!("0x{:08x}", offset));
+ diag
+ }
+ thorin::Error::RelocationWithInvalidSymbol(section, offset) => {
+ diag =
+ handler.struct_err(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol);
+ diag.set_arg("section", section);
+ diag.set_arg("offset", format!("0x{:08x}", offset));
+ diag
+ }
+ thorin::Error::MultipleRelocations(section, offset) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_multiple_relocations);
+ diag.set_arg("section", section);
+ diag.set_arg("offset", format!("0x{:08x}", offset));
+ diag
+ }
+ thorin::Error::UnsupportedRelocation(section, offset) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_unsupported_relocation);
+ diag.set_arg("section", section);
+ diag.set_arg("offset", format!("0x{:08x}", offset));
+ diag
+ }
+ thorin::Error::MissingDwoName(id) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_dwo_name);
+ diag.set_arg("id", format!("0x{:08x}", id));
+ diag
+ }
+ thorin::Error::NoCompilationUnits => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_no_compilation_units);
+ diag
+ }
+ thorin::Error::NoDie => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_no_die);
+ diag
+ }
+ thorin::Error::TopLevelDieNotUnit => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_top_level_die_not_unit);
+ diag
+ }
+ thorin::Error::MissingRequiredSection(section) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_required_section);
+ diag.set_arg("section", section);
+ diag
+ }
+ thorin::Error::ParseUnitAbbreviations(_) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit_abbreviations);
+ diag
+ }
+ thorin::Error::ParseUnitAttribute(_) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit_attribute);
+ diag
+ }
+ thorin::Error::ParseUnitHeader(_) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit_header);
+ diag
+ }
+ thorin::Error::ParseUnit(_) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit);
+ diag
+ }
+ thorin::Error::IncompatibleIndexVersion(section, format, actual) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_incompatible_index_version);
+ diag.set_arg("section", section);
+ diag.set_arg("actual", actual);
+ diag.set_arg("format", format);
+ diag
+ }
+ thorin::Error::OffsetAtIndex(_, index) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_offset_at_index);
+ diag.set_arg("index", index);
+ diag
+ }
+ thorin::Error::StrAtOffset(_, offset) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_str_at_offset);
+ diag.set_arg("offset", format!("0x{:08x}", offset));
+ diag
+ }
+ thorin::Error::ParseIndex(_, section) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_index);
+ diag.set_arg("section", section);
+ diag
+ }
+ thorin::Error::UnitNotInIndex(unit) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_unit_not_in_index);
+ diag.set_arg("unit", format!("0x{:08x}", unit));
+ diag
+ }
+ thorin::Error::RowNotInIndex(_, row) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_row_not_in_index);
+ diag.set_arg("row", row);
+ diag
+ }
+ thorin::Error::SectionNotInRow => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_section_not_in_row);
+ diag
+ }
+ thorin::Error::EmptyUnit(unit) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_empty_unit);
+ diag.set_arg("unit", format!("0x{:08x}", unit));
+ diag
+ }
+ thorin::Error::MultipleDebugInfoSection => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_multiple_debug_info_section);
+ diag
+ }
+ thorin::Error::MultipleDebugTypesSection => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_multiple_debug_types_section);
+ diag
+ }
+ thorin::Error::NotSplitUnit => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_not_split_unit);
+ diag
+ }
+ thorin::Error::DuplicateUnit(unit) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_duplicate_unit);
+ diag.set_arg("unit", format!("0x{:08x}", unit));
+ diag
+ }
+ thorin::Error::MissingReferencedUnit(unit) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_referenced_unit);
+ diag.set_arg("unit", format!("0x{:08x}", unit));
+ diag
+ }
+ thorin::Error::NoOutputObjectCreated => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_not_output_object_created);
+ diag
+ }
+ thorin::Error::MixedInputEncodings => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_mixed_input_encodings);
+ diag
+ }
+ thorin::Error::Io(e) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_io);
+ diag.set_arg("error", format!("{e}"));
+ diag
+ }
+ thorin::Error::ObjectRead(e) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_object_read);
+ diag.set_arg("error", format!("{e}"));
+ diag
+ }
+ thorin::Error::ObjectWrite(e) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_object_write);
+ diag.set_arg("error", format!("{e}"));
+ diag
+ }
+ thorin::Error::GimliRead(e) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_gimli_read);
+ diag.set_arg("error", format!("{e}"));
+ diag
+ }
+ thorin::Error::GimliWrite(e) => {
+ diag = handler.struct_err(fluent::codegen_ssa_thorin_gimli_write);
+ diag.set_arg("error", format!("{e}"));
+ diag
+ }
+ _ => unimplemented!("Untranslated thorin error"),
+ }
+ }
+}
+
+pub struct LinkingFailed<'a> {
+ pub linker_path: &'a PathBuf,
+ pub exit_status: ExitStatus,
+ pub command: &'a Command,
+ pub escaped_output: &'a str,
+}
+
+impl IntoDiagnostic<'_> for LinkingFailed<'_> {
+ fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+ let mut diag = handler.struct_err(fluent::codegen_ssa_linking_failed);
+ diag.set_arg("linker_path", format!("{}", self.linker_path.display()));
+ diag.set_arg("exit_status", format!("{}", self.exit_status));
+
+ diag.note(format!("{:?}", self.command)).note(self.escaped_output);
+
+ // Trying to match an error from OS linkers
+ // which by now we have no way to translate.
+ if self.escaped_output.contains("undefined reference to") {
+ diag.note(fluent::codegen_ssa_extern_funcs_not_found)
+ .note(fluent::codegen_ssa_specify_libraries_to_link)
+ .note(fluent::codegen_ssa_use_cargo_directive);
+ }
+ diag
+ }
+}
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index e736b2aba..ceebe4d41 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -1,12 +1,12 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(box_patterns)]
#![feature(try_blocks)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(once_cell)]
#![feature(associated_type_bounds)]
#![feature(strict_provenance)]
#![feature(int_roundings)]
#![feature(if_let_guard)]
+#![feature(never_type)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
@@ -44,6 +44,7 @@ pub mod base;
pub mod common;
pub mod coverageinfo;
pub mod debuginfo;
+pub mod errors;
pub mod glue;
pub mod meth;
pub mod mir;
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index a6b226ef7..29b7c9b0a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -63,7 +63,9 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
}
}
- fn lltarget<Bx: BuilderMethods<'a, 'tcx>>(
+ /// Get a basic block (creating it if necessary), possibly with a landing
+ /// pad next to it.
+ fn llbb_with_landing_pad<Bx: BuilderMethods<'a, 'tcx>>(
&self,
fx: &mut FunctionCx<'a, 'tcx, Bx>,
target: mir::BasicBlock,
@@ -73,32 +75,36 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
let target_funclet = fx.cleanup_kinds[target].funclet_bb(target);
match (self.funclet_bb, target_funclet) {
(None, None) => (lltarget, false),
- (Some(f), Some(t_f)) if f == t_f || !base::wants_msvc_seh(fx.cx.tcx().sess) => {
- (lltarget, false)
- }
// jump *into* cleanup - need a landing pad if GNU, cleanup pad if MSVC
(None, Some(_)) => (fx.landing_pad_for(target), false),
(Some(_), None) => span_bug!(span, "{:?} - jump out of cleanup?", self.terminator),
- (Some(_), Some(_)) => (fx.landing_pad_for(target), true),
+ (Some(f), Some(t_f)) => {
+ if f == t_f || !base::wants_msvc_seh(fx.cx.tcx().sess) {
+ (lltarget, false)
+ } else {
+ (fx.landing_pad_for(target), true)
+ }
+ }
}
}
- /// Create a basic block.
- fn llblock<Bx: BuilderMethods<'a, 'tcx>>(
+ /// Get a basic block (creating it if necessary), possibly with cleanup
+ /// stuff in it or next to it.
+ fn llbb_with_cleanup<Bx: BuilderMethods<'a, 'tcx>>(
&self,
fx: &mut FunctionCx<'a, 'tcx, Bx>,
target: mir::BasicBlock,
) -> Bx::BasicBlock {
- let (lltarget, is_cleanupret) = self.lltarget(fx, target);
+ let (lltarget, is_cleanupret) = self.llbb_with_landing_pad(fx, target);
if is_cleanupret {
// MSVC cross-funclet jump - need a trampoline
-
- debug!("llblock: creating cleanup trampoline for {:?}", target);
+ debug_assert!(base::wants_msvc_seh(fx.cx.tcx().sess));
+ debug!("llbb_with_cleanup: creating cleanup trampoline for {:?}", target);
let name = &format!("{:?}_cleanup_trampoline_{:?}", self.bb, target);
- let trampoline = Bx::append_block(fx.cx, fx.llfn, name);
- let mut trampoline_bx = Bx::build(fx.cx, trampoline);
+ let trampoline_llbb = Bx::append_block(fx.cx, fx.llfn, name);
+ let mut trampoline_bx = Bx::build(fx.cx, trampoline_llbb);
trampoline_bx.cleanup_ret(self.funclet(fx).unwrap(), Some(lltarget));
- trampoline
+ trampoline_llbb
} else {
lltarget
}
@@ -110,10 +116,11 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
bx: &mut Bx,
target: mir::BasicBlock,
) {
- let (lltarget, is_cleanupret) = self.lltarget(fx, target);
+ let (lltarget, is_cleanupret) = self.llbb_with_landing_pad(fx, target);
if is_cleanupret {
- // micro-optimization: generate a `ret` rather than a jump
+ // MSVC micro-optimization: generate a `ret` rather than a jump
// to a trampoline.
+ debug_assert!(base::wants_msvc_seh(fx.cx.tcx().sess));
bx.cleanup_ret(self.funclet(fx).unwrap(), Some(lltarget));
} else {
bx.br(lltarget);
@@ -138,7 +145,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
let unwind_block = if let Some(cleanup) = cleanup.filter(|_| fn_abi.can_unwind) {
- Some(self.llblock(fx, cleanup))
+ Some(self.llbb_with_cleanup(fx, cleanup))
} else if fx.mir[self.bb].is_cleanup
&& fn_abi.can_unwind
&& !base::wants_msvc_seh(fx.cx.tcx().sess)
@@ -162,9 +169,15 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
} else {
fx.unreachable_block()
};
- let invokeret =
- bx.invoke(fn_ty, fn_ptr, &llargs, ret_llbb, unwind_block, self.funclet(fx));
- bx.apply_attrs_callsite(&fn_abi, invokeret);
+ let invokeret = bx.invoke(
+ fn_ty,
+ Some(&fn_abi),
+ fn_ptr,
+ &llargs,
+ ret_llbb,
+ unwind_block,
+ self.funclet(fx),
+ );
if fx.mir[self.bb].is_cleanup {
bx.do_not_inline(invokeret);
}
@@ -178,8 +191,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
fx.store_return(bx, ret_dest, &fn_abi.ret, invokeret);
}
} else {
- let llret = bx.call(fn_ty, fn_ptr, &llargs, self.funclet(fx));
- bx.apply_attrs_callsite(&fn_abi, llret);
+ let llret = bx.call(fn_ty, 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
@@ -226,7 +238,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
options,
line_spans,
instance,
- Some((ret_llbb, self.llblock(fx, cleanup), self.funclet(fx))),
+ Some((ret_llbb, self.llbb_with_cleanup(fx, cleanup), self.funclet(fx))),
);
} else {
bx.codegen_inline_asm(template, &operands, options, line_spans, instance, None);
@@ -276,8 +288,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if target_iter.len() == 1 {
// If there are two targets (one conditional, one fallback), emit br instead of switch
let (test_value, target) = target_iter.next().unwrap();
- let lltrue = helper.llblock(self, target);
- let llfalse = helper.llblock(self, targets.otherwise());
+ let lltrue = helper.llbb_with_cleanup(self, target);
+ let llfalse = helper.llbb_with_cleanup(self, targets.otherwise());
if switch_ty == bx.tcx().types.bool {
// Don't generate trivial icmps when switching on bool
match test_value {
@@ -294,8 +306,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} else {
bx.switch(
discr.immediate(),
- helper.llblock(self, targets.otherwise()),
- target_iter.map(|(value, target)| (value, helper.llblock(self, target))),
+ helper.llbb_with_cleanup(self, targets.otherwise()),
+ target_iter.map(|(value, target)| (value, helper.llbb_with_cleanup(self, target))),
);
}
}
@@ -525,7 +537,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let cond = bx.expect(cond, expected);
// Create the failure block and the conditional branch to it.
- let lltarget = helper.llblock(self, target);
+ let lltarget = helper.llbb_with_cleanup(self, target);
let panic_block = bx.append_sibling_block("panic");
if expected {
bx.cond_br(cond, lltarget, panic_block);
@@ -1454,20 +1466,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// bar();
// }
Some(&mir::TerminatorKind::Abort) => {
- let cs_bb =
+ let cs_llbb =
Bx::append_block(self.cx, self.llfn, &format!("cs_funclet{:?}", bb));
- let cp_bb =
+ let cp_llbb =
Bx::append_block(self.cx, self.llfn, &format!("cp_funclet{:?}", bb));
- ret_llbb = cs_bb;
+ ret_llbb = cs_llbb;
- let mut cs_bx = Bx::build(self.cx, cs_bb);
- let cs = cs_bx.catch_switch(None, None, &[cp_bb]);
+ let mut cs_bx = Bx::build(self.cx, cs_llbb);
+ let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
// The "null" here is actually a RTTI type descriptor for the
// C++ personality function, but `catch (...)` has no type so
// it's null. The 64 here is actually a bitfield which
// represents that this is a catch-all block.
- let mut cp_bx = Bx::build(self.cx, cp_bb);
+ let mut cp_bx = Bx::build(self.cx, cp_llbb);
let null = cp_bx.const_null(
cp_bx.type_i8p_ext(cp_bx.cx().data_layout().instruction_address_space),
);
@@ -1476,10 +1488,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
cp_bx.br(llbb);
}
_ => {
- let cleanup_bb =
+ let cleanup_llbb =
Bx::append_block(self.cx, self.llfn, &format!("funclet_{:?}", bb));
- ret_llbb = cleanup_bb;
- let mut cleanup_bx = Bx::build(self.cx, cleanup_bb);
+ ret_llbb = cleanup_llbb;
+ let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb);
funclet = cleanup_bx.cleanup_pad(None, &[]);
cleanup_bx.br(llbb);
}
@@ -1487,19 +1499,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.funclets[bb] = Some(funclet);
ret_llbb
} else {
- let bb = Bx::append_block(self.cx, self.llfn, "cleanup");
- let mut bx = Bx::build(self.cx, bb);
+ let cleanup_llbb = Bx::append_block(self.cx, self.llfn, "cleanup");
+ let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb);
let llpersonality = self.cx.eh_personality();
let llretty = self.landing_pad_type();
- let lp = bx.cleanup_landing_pad(llretty, llpersonality);
+ let lp = cleanup_bx.cleanup_landing_pad(llretty, llpersonality);
- let slot = self.get_personality_slot(&mut bx);
- slot.storage_live(&mut bx);
- Pair(bx.extract_value(lp, 0), bx.extract_value(lp, 1)).store(&mut bx, slot);
+ let slot = self.get_personality_slot(&mut cleanup_bx);
+ slot.storage_live(&mut cleanup_bx);
+ Pair(cleanup_bx.extract_value(lp, 0), cleanup_bx.extract_value(lp, 1))
+ .store(&mut cleanup_bx, slot);
- bx.br(llbb);
- bx.llbb()
+ cleanup_bx.br(llbb);
+ cleanup_llbb
}
}
@@ -1533,8 +1546,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicNoUnwind);
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
- let llret = bx.call(fn_ty, fn_ptr, &[], None);
- bx.apply_attrs_callsite(&fn_abi, llret);
+ let llret = bx.call(fn_ty, Some(&fn_abi), fn_ptr, &[], None);
bx.do_not_inline(llret);
bx.unreachable();
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 2b931bfc9..da9aaf00e 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -148,10 +148,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let debug_context = cx.create_function_debug_context(instance, &fn_abi, llfn, &mir);
let start_llbb = Bx::append_block(cx, llfn, "start");
- let mut bx = Bx::build(cx, start_llbb);
+ let mut start_bx = Bx::build(cx, start_llbb);
if mir.basic_blocks.iter().any(|bb| bb.is_cleanup) {
- bx.set_personality_fn(cx.eh_personality());
+ start_bx.set_personality_fn(cx.eh_personality());
}
let cleanup_kinds = analyze::cleanup_kinds(&mir);
@@ -180,7 +180,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
caller_location: None,
};
- fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut bx);
+ fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx);
// Evaluate all required consts; codegen later assumes that CTFE will never fail.
let mut all_consts_ok = true;
@@ -206,29 +206,29 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// Allocate variable and temp allocas
fx.locals = {
- let args = arg_local_refs(&mut bx, &mut fx, &memory_locals);
+ let args = arg_local_refs(&mut start_bx, &mut fx, &memory_locals);
let mut allocate_local = |local| {
let decl = &mir.local_decls[local];
- let layout = bx.layout_of(fx.monomorphize(decl.ty));
+ let layout = start_bx.layout_of(fx.monomorphize(decl.ty));
assert!(!layout.ty.has_erasable_regions());
if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() {
debug!("alloc: {:?} (return place) -> place", local);
- let llretptr = bx.get_param(0);
+ let llretptr = start_bx.get_param(0);
return LocalRef::Place(PlaceRef::new_sized(llretptr, layout));
}
if memory_locals.contains(local) {
debug!("alloc: {:?} -> place", local);
if layout.is_unsized() {
- LocalRef::UnsizedPlace(PlaceRef::alloca_unsized_indirect(&mut bx, layout))
+ LocalRef::UnsizedPlace(PlaceRef::alloca_unsized_indirect(&mut start_bx, layout))
} else {
- LocalRef::Place(PlaceRef::alloca(&mut bx, layout))
+ LocalRef::Place(PlaceRef::alloca(&mut start_bx, layout))
}
} else {
debug!("alloc: {:?} -> operand", local);
- LocalRef::new_operand(&mut bx, layout)
+ LocalRef::new_operand(&mut start_bx, layout)
}
};
@@ -240,7 +240,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
};
// Apply debuginfo to the newly allocated locals.
- fx.debug_introduce_locals(&mut bx);
+ fx.debug_introduce_locals(&mut start_bx);
// Codegen the body of each block using reverse postorder
for (bb, _) in traversal::reverse_postorder(&mir) {
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 37b1e0362..e6ba642a7 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -352,7 +352,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
// 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.array_alloca(bx.cx().type_i8(), llsize, max_align);
+ let lldst = bx.byte_array_alloca(llsize, max_align);
bx.memcpy(lldst, max_align, llptr, min_align, llsize, flags);
// Store the allocated region and the extra to the indirect place.
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 13d8f6edd..9c18df564 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -400,6 +400,21 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
downcast
}
+ pub fn project_type<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
+ &self,
+ bx: &mut Bx,
+ ty: Ty<'tcx>,
+ ) -> Self {
+ let mut downcast = *self;
+ downcast.layout = bx.cx().layout_of(ty);
+
+ // Cast to the appropriate type.
+ let variant_ty = bx.cx().backend_type(downcast.layout);
+ downcast.llval = bx.pointercast(downcast.llval, bx.cx().type_ptr_to(variant_ty));
+
+ downcast
+ }
+
pub fn storage_live<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) {
bx.lifetime_start(self.llval, self.layout.size);
}
@@ -442,6 +457,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mir::ProjectionElem::Field(ref field, _) => {
cg_base.project_field(bx, field.index())
}
+ mir::ProjectionElem::OpaqueCast(ty) => cg_base.project_type(bx, ty),
mir::ProjectionElem::Index(index) => {
let index = &mir::Operand::Copy(mir::Place::from(index));
let index = self.codegen_operand(bx, index);
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 56852b0fc..4aab31fbf 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -4,7 +4,6 @@ use super::{FunctionCx, LocalRef};
use crate::base;
use crate::common::{self, IntPredicate};
-use crate::meth::get_vtable;
use crate::traits::*;
use crate::MemFlags;
@@ -250,7 +249,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
OperandValue::Pair(lldata, llextra)
}
mir::CastKind::Pointer(PointerCast::MutToConstPointer)
- | mir::CastKind::Misc
+ | mir::CastKind::PtrToPtr
if bx.cx().is_backend_scalar_pair(operand.layout) =>
{
if let OperandValue::Pair(data_ptr, meta) = operand.val {
@@ -273,24 +272,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
mir::CastKind::DynStar => {
- let data = match operand.val {
+ let (lldata, llextra) = match operand.val {
OperandValue::Ref(_, _, _) => todo!(),
- OperandValue::Immediate(v) => v,
- OperandValue::Pair(_, _) => todo!(),
+ OperandValue::Immediate(v) => (v, None),
+ OperandValue::Pair(v, l) => (v, Some(l)),
};
- let trait_ref =
- if let ty::Dynamic(data, _, ty::DynStar) = cast.ty.kind() {
- data.principal()
- } else {
- bug!("Only valid to do a DynStar cast into a DynStar type")
- };
- let vtable = get_vtable(bx.cx(), source.ty(self.mir, bx.tcx()), trait_ref);
- OperandValue::Pair(data, vtable)
+ let (lldata, llextra) =
+ base::cast_to_dyn_star(&mut bx, lldata, operand.layout, cast.ty, llextra);
+ OperandValue::Pair(lldata, llextra)
}
mir::CastKind::Pointer(
PointerCast::MutToConstPointer | PointerCast::ArrayToPointer,
)
- | mir::CastKind::Misc
+ | mir::CastKind::IntToInt
+ | mir::CastKind::FloatToInt
+ | mir::CastKind::FloatToFloat
+ | mir::CastKind::IntToFloat
+ | mir::CastKind::PtrToPtr
+ | mir::CastKind::FnPtrToPtr
+
// Since int2ptr can have arbitrary integer types as input (so we have to do
// sign extension and all that), it is currently best handled in the same code
// path as the other integer-to-X casts.
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 0e259bcd1..83407ee8f 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -13,17 +13,25 @@ pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
// if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted
const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+ // tidy-alphabetical-start
("aclass", Some(sym::arm_target_feature)),
- ("mclass", Some(sym::arm_target_feature)),
- ("rclass", Some(sym::arm_target_feature)),
- ("dsp", Some(sym::arm_target_feature)),
- ("neon", Some(sym::arm_target_feature)),
+ ("aes", Some(sym::arm_target_feature)),
("crc", Some(sym::arm_target_feature)),
("crypto", Some(sym::arm_target_feature)),
- ("aes", Some(sym::arm_target_feature)),
- ("sha2", Some(sym::arm_target_feature)),
- ("i8mm", Some(sym::arm_target_feature)),
+ ("d32", Some(sym::arm_target_feature)),
("dotprod", Some(sym::arm_target_feature)),
+ ("dsp", Some(sym::arm_target_feature)),
+ ("fp-armv8", Some(sym::arm_target_feature)),
+ ("i8mm", Some(sym::arm_target_feature)),
+ ("mclass", Some(sym::arm_target_feature)),
+ ("neon", Some(sym::arm_target_feature)),
+ ("rclass", Some(sym::arm_target_feature)),
+ ("sha2", Some(sym::arm_target_feature)),
+ // This is needed for inline assembly, but shouldn't be stabilized as-is
+ // since it should be enabled per-function using #[instruction_set], not
+ // #[target_feature].
+ ("thumb-mode", Some(sym::arm_target_feature)),
+ ("thumb2", Some(sym::arm_target_feature)),
("v5te", Some(sym::arm_target_feature)),
("v6", Some(sym::arm_target_feature)),
("v6k", Some(sym::arm_target_feature)),
@@ -33,104 +41,97 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("vfp2", Some(sym::arm_target_feature)),
("vfp3", Some(sym::arm_target_feature)),
("vfp4", Some(sym::arm_target_feature)),
- ("fp-armv8", Some(sym::arm_target_feature)),
- // This is needed for inline assembly, but shouldn't be stabilized as-is
- // since it should be enabled per-function using #[instruction_set], not
- // #[target_feature].
- ("thumb-mode", Some(sym::arm_target_feature)),
- ("thumb2", Some(sym::arm_target_feature)),
- ("d32", Some(sym::arm_target_feature)),
+ // tidy-alphabetical-end
];
const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
- // FEAT_AdvSimd & FEAT_FP
- ("neon", None),
- // FEAT_FP16
- ("fp16", None),
- // FEAT_SVE
- ("sve", None),
+ // tidy-alphabetical-start
+ // FEAT_AES
+ ("aes", None),
+ // FEAT_BF16
+ ("bf16", None),
+ // FEAT_BTI
+ ("bti", None),
// FEAT_CRC
("crc", None),
- // FEAT_RAS
- ("ras", None),
- // FEAT_LSE
- ("lse", None),
- // FEAT_RDM
- ("rdm", None),
- // FEAT_RCPC
- ("rcpc", None),
- // FEAT_RCPC2
- ("rcpc2", None),
- // FEAT_DotProd
- ("dotprod", None),
- // FEAT_TME
- ("tme", None),
- // FEAT_FHM
- ("fhm", None),
// FEAT_DIT
("dit", None),
- // FEAT_FLAGM
- ("flagm", None),
- // FEAT_SSBS
- ("ssbs", None),
- // FEAT_SB
- ("sb", None),
- // FEAT_PAUTH (address authentication)
- ("paca", None),
- // FEAT_PAUTH (generic authentication)
- ("pacg", None),
+ // FEAT_DotProd
+ ("dotprod", None),
// FEAT_DPB
("dpb", None),
// FEAT_DPB2
("dpb2", None),
- // FEAT_SVE2
- ("sve2", None),
- // FEAT_SVE2_AES
- ("sve2-aes", None),
- // FEAT_SVE2_SM4
- ("sve2-sm4", None),
- // FEAT_SVE2_SHA3
- ("sve2-sha3", None),
- // FEAT_SVE2_BitPerm
- ("sve2-bitperm", None),
- // FEAT_FRINTTS
- ("frintts", None),
- // FEAT_I8MM
- ("i8mm", None),
// FEAT_F32MM
("f32mm", None),
// FEAT_F64MM
("f64mm", None),
- // FEAT_BF16
- ("bf16", None),
- // FEAT_RAND
- ("rand", None),
- // FEAT_BTI
- ("bti", None),
- // FEAT_MTE
- ("mte", None),
- // FEAT_JSCVT
- ("jsconv", None),
// FEAT_FCMA
("fcma", None),
- // FEAT_AES
- ("aes", None),
+ // FEAT_FHM
+ ("fhm", None),
+ // FEAT_FLAGM
+ ("flagm", None),
+ // FEAT_FP16
+ ("fp16", None),
+ // FEAT_FRINTTS
+ ("frintts", None),
+ // FEAT_I8MM
+ ("i8mm", None),
+ // FEAT_JSCVT
+ ("jsconv", None),
+ // FEAT_LOR
+ ("lor", None),
+ // FEAT_LSE
+ ("lse", None),
+ // FEAT_MTE
+ ("mte", None),
+ // FEAT_AdvSimd & FEAT_FP
+ ("neon", None),
+ // FEAT_PAUTH (address authentication)
+ ("paca", None),
+ // FEAT_PAUTH (generic authentication)
+ ("pacg", None),
+ // FEAT_PAN
+ ("pan", None),
+ // FEAT_PMUv3
+ ("pmuv3", None),
+ // FEAT_RAND
+ ("rand", None),
+ // FEAT_RAS
+ ("ras", None),
+ // FEAT_RCPC
+ ("rcpc", None),
+ // FEAT_RCPC2
+ ("rcpc2", None),
+ // FEAT_RDM
+ ("rdm", None),
+ // FEAT_SB
+ ("sb", None),
// FEAT_SHA1 & FEAT_SHA256
("sha2", None),
// FEAT_SHA512 & FEAT_SHA3
("sha3", None),
// FEAT_SM3 & FEAT_SM4
("sm4", None),
- // FEAT_PAN
- ("pan", None),
- // FEAT_LOR
- ("lor", None),
- // FEAT_VHE
- ("vh", None),
- // FEAT_PMUv3
- ("pmuv3", None),
// FEAT_SPE
("spe", None),
+ // FEAT_SSBS
+ ("ssbs", None),
+ // FEAT_SVE
+ ("sve", None),
+ // FEAT_SVE2
+ ("sve2", None),
+ // FEAT_SVE2_AES
+ ("sve2-aes", None),
+ // FEAT_SVE2_BitPerm
+ ("sve2-bitperm", None),
+ // FEAT_SVE2_SHA3
+ ("sve2-sha3", None),
+ // FEAT_SVE2_SM4
+ ("sve2-sm4", None),
+ // FEAT_TME
+ ("tme", None),
("v8.1a", Some(sym::aarch64_ver_target_feature)),
("v8.2a", Some(sym::aarch64_ver_target_feature)),
("v8.3a", Some(sym::aarch64_ver_target_feature)),
@@ -138,6 +139,9 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("v8.5a", Some(sym::aarch64_ver_target_feature)),
("v8.6a", Some(sym::aarch64_ver_target_feature)),
("v8.7a", Some(sym::aarch64_ver_target_feature)),
+ // FEAT_VHE
+ ("vh", None),
+ // tidy-alphabetical-end
];
const AARCH64_TIED_FEATURES: &[&[&str]] = &[
@@ -145,6 +149,7 @@ const AARCH64_TIED_FEATURES: &[&[&str]] = &[
];
const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+ // tidy-alphabetical-start
("adx", None),
("aes", None),
("avx", None),
@@ -194,69 +199,80 @@ const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("xsavec", None),
("xsaveopt", None),
("xsaves", None),
+ // tidy-alphabetical-end
];
const HEXAGON_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+ // tidy-alphabetical-start
("hvx", Some(sym::hexagon_target_feature)),
("hvx-length128b", Some(sym::hexagon_target_feature)),
+ // tidy-alphabetical-end
];
const POWERPC_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+ // tidy-alphabetical-start
("altivec", Some(sym::powerpc_target_feature)),
("power8-altivec", Some(sym::powerpc_target_feature)),
- ("power9-altivec", Some(sym::powerpc_target_feature)),
("power8-vector", Some(sym::powerpc_target_feature)),
+ ("power9-altivec", Some(sym::powerpc_target_feature)),
("power9-vector", Some(sym::powerpc_target_feature)),
("vsx", Some(sym::powerpc_target_feature)),
+ // tidy-alphabetical-end
];
const MIPS_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+ // tidy-alphabetical-start
("fp64", Some(sym::mips_target_feature)),
("msa", Some(sym::mips_target_feature)),
("virt", Some(sym::mips_target_feature)),
+ // tidy-alphabetical-end
];
const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
- ("m", Some(sym::riscv_target_feature)),
+ // tidy-alphabetical-start
("a", Some(sym::riscv_target_feature)),
("c", Some(sym::riscv_target_feature)),
- ("f", Some(sym::riscv_target_feature)),
("d", Some(sym::riscv_target_feature)),
("e", Some(sym::riscv_target_feature)),
+ ("f", Some(sym::riscv_target_feature)),
+ ("m", Some(sym::riscv_target_feature)),
("v", Some(sym::riscv_target_feature)),
- ("zfinx", Some(sym::riscv_target_feature)),
- ("zdinx", Some(sym::riscv_target_feature)),
- ("zhinx", Some(sym::riscv_target_feature)),
- ("zhinxmin", Some(sym::riscv_target_feature)),
- ("zfh", Some(sym::riscv_target_feature)),
- ("zfhmin", Some(sym::riscv_target_feature)),
("zba", Some(sym::riscv_target_feature)),
("zbb", Some(sym::riscv_target_feature)),
("zbc", Some(sym::riscv_target_feature)),
- ("zbs", Some(sym::riscv_target_feature)),
("zbkb", Some(sym::riscv_target_feature)),
("zbkc", Some(sym::riscv_target_feature)),
("zbkx", Some(sym::riscv_target_feature)),
+ ("zbs", Some(sym::riscv_target_feature)),
+ ("zdinx", Some(sym::riscv_target_feature)),
+ ("zfh", Some(sym::riscv_target_feature)),
+ ("zfhmin", Some(sym::riscv_target_feature)),
+ ("zfinx", Some(sym::riscv_target_feature)),
+ ("zhinx", Some(sym::riscv_target_feature)),
+ ("zhinxmin", Some(sym::riscv_target_feature)),
+ ("zk", Some(sym::riscv_target_feature)),
+ ("zkn", Some(sym::riscv_target_feature)),
("zknd", Some(sym::riscv_target_feature)),
("zkne", Some(sym::riscv_target_feature)),
("zknh", Some(sym::riscv_target_feature)),
- ("zksed", Some(sym::riscv_target_feature)),
- ("zksh", Some(sym::riscv_target_feature)),
("zkr", Some(sym::riscv_target_feature)),
- ("zkn", Some(sym::riscv_target_feature)),
("zks", Some(sym::riscv_target_feature)),
- ("zk", Some(sym::riscv_target_feature)),
+ ("zksed", Some(sym::riscv_target_feature)),
+ ("zksh", Some(sym::riscv_target_feature)),
("zkt", Some(sym::riscv_target_feature)),
+ // tidy-alphabetical-end
];
const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
- ("simd128", None),
+ // tidy-alphabetical-start
("atomics", Some(sym::wasm_target_feature)),
- ("nontrapping-fptoint", Some(sym::wasm_target_feature)),
("bulk-memory", Some(sym::wasm_target_feature)),
("mutable-globals", Some(sym::wasm_target_feature)),
+ ("nontrapping-fptoint", Some(sym::wasm_target_feature)),
("reference-types", Some(sym::wasm_target_feature)),
("sign-ext", Some(sym::wasm_target_feature)),
+ ("simd128", None),
+ // tidy-alphabetical-end
];
const BPF_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[("alu32", Some(sym::bpf_target_feature))];
diff --git a/compiler/rustc_codegen_ssa/src/traits/abi.rs b/compiler/rustc_codegen_ssa/src/traits/abi.rs
index a00d78daf..60d8f2a9e 100644
--- a/compiler/rustc_codegen_ssa/src/traits/abi.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/abi.rs
@@ -1,8 +1,5 @@
use super::BackendTypes;
-use rustc_middle::ty::Ty;
-use rustc_target::abi::call::FnAbi;
pub trait AbiBuilderMethods<'tcx>: BackendTypes {
- fn apply_attrs_callsite(&mut self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, callsite: Self::Value);
fn get_param(&mut self, index: usize) -> Self::Value;
}
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 779bd3ea2..87e347c61 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -134,8 +134,6 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se
opt_level: config::OptLevel,
target_features: &[String],
) -> TargetMachineFactoryFn<Self>;
- fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str;
- fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str>;
fn spawn_thread<F, T>(_time_trace: bool, f: F) -> std::thread::JoinHandle<T>
where
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 10cf8948b..01408f39f 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -17,6 +17,7 @@ use crate::MemFlags;
use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout};
use rustc_middle::ty::Ty;
use rustc_span::Span;
+use rustc_target::abi::call::FnAbi;
use rustc_target::abi::{Abi, Align, Scalar, Size, WrappingRange};
use rustc_target::spec::HasTargetSpec;
@@ -71,6 +72,7 @@ pub trait BuilderMethods<'a, 'tcx>:
fn invoke(
&mut self,
llty: Self::Type,
+ fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
llfn: Self::Value,
args: &[Self::Value],
then: Self::BasicBlock,
@@ -133,8 +135,7 @@ pub trait BuilderMethods<'a, 'tcx>:
fn to_immediate_scalar(&mut self, val: Self::Value, scalar: Scalar) -> Self::Value;
fn alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value;
- fn dynamic_alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value;
- fn array_alloca(&mut self, ty: Self::Type, len: Self::Value, align: Align) -> Self::Value;
+ fn byte_array_alloca(&mut self, len: Self::Value, align: Align) -> Self::Value;
fn load(&mut self, ty: Self::Type, ptr: Self::Value, align: Align) -> Self::Value;
fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value) -> Self::Value;
@@ -320,6 +321,7 @@ pub trait BuilderMethods<'a, 'tcx>:
fn call(
&mut self,
llty: Self::Type,
+ fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
llfn: Self::Value,
args: &[Self::Value],
funclet: Option<&Self::Funclet>,
diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
index 7755e6793..450672fb9 100644
--- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
@@ -5,7 +5,7 @@ use rustc_span::Span;
use rustc_target::abi::call::FnAbi;
pub trait IntrinsicCallMethods<'tcx>: BackendTypes {
- /// Remember to add all intrinsics here, in `compiler/rustc_typeck/src/check/mod.rs`,
+ /// Remember to add all intrinsics here, in `compiler/rustc_hir_analysis/src/check/mod.rs`,
/// and in `library/core/src/intrinsics.rs`; if you need access to any LLVM intrinsics,
/// add them to `compiler/rustc_codegen_llvm/src/context.rs`.
fn codegen_intrinsic_call(
diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs
index 4266e42ec..04e2b8796 100644
--- a/compiler/rustc_codegen_ssa/src/traits/misc.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs
@@ -15,12 +15,8 @@ pub trait MiscMethods<'tcx>: BackendTypes {
fn eh_personality(&self) -> Self::Value;
fn sess(&self) -> &Session;
fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx>;
- fn used_statics(&self) -> &RefCell<Vec<Self::Value>>;
- fn compiler_used_statics(&self) -> &RefCell<Vec<Self::Value>>;
fn set_frame_pointer_type(&self, llfn: Self::Function);
fn apply_target_cpu_attr(&self, llfn: Self::Function);
- fn create_used_variable(&self);
- fn create_compiler_used_variable(&self);
/// Declares the extern "C" main function for the entry point. Returns None if the symbol already exists.
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function>;
}
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index 8158e8dd0..bdc6a91cf 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -5,7 +5,6 @@ use crate::common::TypeKind;
use crate::mir::place::PlaceRef;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, Ty};
-use rustc_span::DUMMY_SP;
use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg};
use rustc_target::abi::{AddressSpace, Integer};
@@ -75,16 +74,16 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
}
fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
- ty.is_sized(self.tcx().at(DUMMY_SP), ty::ParamEnv::reveal_all())
+ ty.is_sized(self.tcx(), ty::ParamEnv::reveal_all())
}
fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
- ty.is_freeze(self.tcx().at(DUMMY_SP), ty::ParamEnv::reveal_all())
+ ty.is_freeze(self.tcx(), ty::ParamEnv::reveal_all())
}
fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool {
let param_env = ty::ParamEnv::reveal_all();
- if ty.is_sized(self.tcx().at(DUMMY_SP), param_env) {
+ if ty.is_sized(self.tcx(), param_env) {
return false;
}
diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs
index e54ec34f1..e0e8ffa89 100644
--- a/compiler/rustc_codegen_ssa/src/traits/write.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/write.rs
@@ -9,7 +9,6 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
type Module: Send + Sync;
type TargetMachine;
type ModuleBuffer: ModuleBufferMethods;
- type Context: ?Sized;
type ThinData: Send + Sync;
type ThinBuffer: ThinBufferMethods;
diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml
index 32e8233a0..e09a6d1d6 100644
--- a/compiler/rustc_const_eval/Cargo.toml
+++ b/compiler/rustc_const_eval/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
tracing = "0.1"
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 09d53331b..4977a5d6b 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -2,7 +2,6 @@ use std::error::Error;
use std::fmt;
use rustc_errors::Diagnostic;
-use rustc_hir as hir;
use rustc_middle::mir::AssertKind;
use rustc_middle::ty::{layout::LayoutError, query::TyCtxtAt, ConstInt};
use rustc_span::{Span, Symbol};
@@ -23,11 +22,7 @@ pub enum ConstEvalErrKind {
Abort(String),
}
-impl MachineStopType for ConstEvalErrKind {
- fn is_hard_err(&self) -> bool {
- matches!(self, Self::Panic { .. })
- }
-}
+impl MachineStopType for ConstEvalErrKind {}
// The errors become `MachineStop` with plain strings when being raised.
// `ConstEvalErr` (in `librustc_middle/mir/interpret/error.rs`) knows to
@@ -69,7 +64,7 @@ pub struct ConstEvalErr<'tcx> {
impl<'tcx> ConstEvalErr<'tcx> {
/// Turn an interpreter error into something to report to the user.
/// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace.
- /// Should be called only if the error is actually going to to be reported!
+ /// Should be called only if the error is actually going to be reported!
pub fn new<'mir, M: Machine<'mir, 'tcx>>(
ecx: &InterpCx<'mir, 'tcx, M>,
error: InterpErrorInfo<'tcx>,
@@ -87,48 +82,10 @@ impl<'tcx> ConstEvalErr<'tcx> {
ConstEvalErr { error: error.into_kind(), stacktrace, span }
}
- pub fn struct_error(
- &self,
- tcx: TyCtxtAt<'tcx>,
- message: &str,
- decorate: impl FnOnce(&mut Diagnostic),
- ) -> ErrorHandled {
- self.struct_generic(tcx, message, decorate, None)
- }
-
pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
self.struct_error(tcx, message, |_| {})
}
- pub fn report_as_lint(
- &self,
- tcx: TyCtxtAt<'tcx>,
- message: &str,
- lint_root: hir::HirId,
- span: Option<Span>,
- ) -> ErrorHandled {
- self.struct_generic(
- tcx,
- message,
- |lint: &mut Diagnostic| {
- // Apply the span.
- if let Some(span) = span {
- let primary_spans = lint.span.primary_spans().to_vec();
- // point at the actual error as the primary span
- lint.replace_span_with(span);
- // point to the `const` statement as a secondary span
- // they don't have any label
- for sp in primary_spans {
- if sp != span {
- lint.span_label(sp, "");
- }
- }
- }
- },
- Some(lint_root),
- )
- }
-
/// Create a diagnostic for this const eval error.
///
/// Sets the message passed in via `message` and adds span labels with detailed error
@@ -137,13 +94,12 @@ impl<'tcx> ConstEvalErr<'tcx> {
///
/// If `lint_root.is_some()` report it as a lint, else report it as a hard error.
/// (Except that for some errors, we ignore all that -- see `must_error` below.)
- #[instrument(skip(self, tcx, decorate, lint_root), level = "debug")]
- fn struct_generic(
+ #[instrument(skip(self, tcx, decorate), level = "debug")]
+ pub fn struct_error(
&self,
tcx: TyCtxtAt<'tcx>,
message: &str,
decorate: impl FnOnce(&mut Diagnostic),
- lint_root: Option<hir::HirId>,
) -> ErrorHandled {
let finish = |err: &mut Diagnostic, span_msg: Option<String>| {
trace!("reporting const eval failure at {:?}", self.span);
@@ -224,27 +180,9 @@ impl<'tcx> ConstEvalErr<'tcx> {
let err_msg = self.error.to_string();
- // Regular case - emit a lint.
- if let Some(lint_root) = lint_root {
- // Report as lint.
- let hir_id =
- self.stacktrace.iter().rev().find_map(|frame| frame.lint_root).unwrap_or(lint_root);
- tcx.struct_span_lint_hir(
- rustc_session::lint::builtin::CONST_ERR,
- hir_id,
- tcx.span,
- |lint| {
- let mut lint = lint.build(message);
- finish(&mut lint, Some(err_msg));
- lint.emit();
- },
- );
- ErrorHandled::Linted
- } else {
- // Report as hard error.
- let mut err = struct_error(tcx, message);
- finish(&mut err, Some(err_msg));
- ErrorHandled::Reported(err.emit())
- }
+ // Report as hard error.
+ let mut err = struct_error(tcx, message);
+ finish(&mut err, Some(err_msg));
+ ErrorHandled::Reported(err.emit())
}
}
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 a2f14e753..1b1052fdf 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -13,7 +13,7 @@ use rustc_middle::mir::pretty::display_allocation;
use rustc_middle::traits::Reveal;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, subst::Subst, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
use rustc_span::source_map::Span;
use rustc_target::abi::{self, Abi};
use std::borrow::Cow;
@@ -317,45 +317,23 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) {
Err(error) => {
let err = ConstEvalErr::new(&ecx, error, None);
- // Some CTFE errors raise just a lint, not a hard error; see
- // <https://github.com/rust-lang/rust/issues/71800>.
- let is_hard_err = if let Some(def) = def.as_local() {
- // (Associated) consts only emit a lint, since they might be unused.
- !matches!(tcx.def_kind(def.did.to_def_id()), DefKind::Const | DefKind::AssocConst)
- // check if the inner InterpError is hard
- || err.error.is_hard_err()
+ let msg = if is_static {
+ Cow::from("could not evaluate static initializer")
} else {
- // use of broken constant from other crate: always an error
- true
- };
-
- if is_hard_err {
- let msg = if is_static {
- Cow::from("could not evaluate static initializer")
+ // If the current item has generics, we'd like to enrich the message with the
+ // instance and its substs: to show the actual compile-time values, in addition to
+ // the expression, leading to the const eval error.
+ let instance = &key.value.instance;
+ if !instance.substs.is_empty() {
+ let instance = with_no_trimmed_paths!(instance.to_string());
+ let msg = format!("evaluation of `{}` failed", instance);
+ Cow::from(msg)
} else {
- // If the current item has generics, we'd like to enrich the message with the
- // instance and its substs: to show the actual compile-time values, in addition to
- // the expression, leading to the const eval error.
- let instance = &key.value.instance;
- if !instance.substs.is_empty() {
- let instance = with_no_trimmed_paths!(instance.to_string());
- let msg = format!("evaluation of `{}` failed", instance);
- Cow::from(msg)
- } else {
- Cow::from("evaluation of constant value failed")
- }
- };
+ Cow::from("evaluation of constant value failed")
+ }
+ };
- Err(err.report_as_error(ecx.tcx.at(err.span), &msg))
- } else {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def.as_local().unwrap().did);
- Err(err.report_as_lint(
- tcx.at(tcx.def_span(def.did)),
- "any use of this value will cause an error",
- hir_id,
- Some(err.span),
- ))
- }
+ Err(err.report_as_error(ecx.tcx.at(err.span), &msg))
}
Ok(mplace) => {
// Since evaluation had no errors, validate the resulting constant.
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index e5acacd91..35d58d2f6 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -2,10 +2,10 @@ use rustc_hir::def::DefKind;
use rustc_middle::mir;
use rustc_middle::ty::{self, Ty, TyCtxt};
use std::borrow::Borrow;
-use std::collections::hash_map::Entry;
use std::hash::Hash;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::fx::IndexEntry;
use std::fmt;
use rustc_ast::Mutability;
@@ -107,18 +107,18 @@ impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
}
}
-impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
+impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxIndexMap<K, V> {
#[inline(always)]
fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
where
K: Borrow<Q>,
{
- FxHashMap::contains_key(self, k)
+ FxIndexMap::contains_key(self, k)
}
#[inline(always)]
fn insert(&mut self, k: K, v: V) -> Option<V> {
- FxHashMap::insert(self, k, v)
+ FxIndexMap::insert(self, k, v)
}
#[inline(always)]
@@ -126,7 +126,7 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
where
K: Borrow<Q>,
{
- FxHashMap::remove(self, k)
+ FxIndexMap::remove(self, k)
}
#[inline(always)]
@@ -148,8 +148,8 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
#[inline(always)]
fn get_mut_or<E>(&mut self, k: K, vacant: impl FnOnce() -> Result<V, E>) -> Result<&mut V, E> {
match self.entry(k) {
- Entry::Occupied(e) => Ok(e.into_mut()),
- Entry::Vacant(e) => {
+ IndexEntry::Occupied(e) => Ok(e.into_mut()),
+ IndexEntry::Vacant(e) => {
let v = vacant()?;
Ok(e.insert(v))
}
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index d9c4ae4d5..1c33e7845 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -100,10 +100,10 @@ pub(crate) fn try_destructure_mir_constant<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
val: mir::ConstantKind<'tcx>,
-) -> InterpResult<'tcx, mir::DestructuredMirConstant<'tcx>> {
+) -> InterpResult<'tcx, mir::DestructuredConstant<'tcx>> {
trace!("destructure_mir_constant: {:?}", val);
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
- let op = ecx.mir_const_to_op(&val, None)?;
+ let op = ecx.const_to_op(&val, None)?;
// We go to `usize` as we cannot allocate anything bigger anyway.
let (field_count, variant, down) = match val.ty().kind() {
@@ -129,7 +129,7 @@ pub(crate) fn try_destructure_mir_constant<'tcx>(
.collect::<InterpResult<'tcx, Vec<_>>>()?;
let fields = tcx.arena.alloc_from_iter(fields_iter);
- Ok(mir::DestructuredMirConstant { variant, fields })
+ Ok(mir::DestructuredConstant { variant, fields })
}
#[instrument(skip(tcx), level = "debug")]
@@ -139,7 +139,7 @@ pub(crate) fn deref_mir_constant<'tcx>(
val: mir::ConstantKind<'tcx>,
) -> mir::ConstantKind<'tcx> {
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
- let op = ecx.mir_const_to_op(&val, None).unwrap();
+ let op = ecx.const_to_op(&val, None).unwrap();
let mplace = ecx.deref_operand(&op).unwrap();
if let Some(alloc_id) = mplace.ptr.provenance {
assert_eq!(
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index a964fe846..f4da11883 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -212,7 +212,7 @@ fn create_pointee_place<'tcx>(
) -> MPlaceTy<'tcx> {
let tcx = ecx.tcx.tcx;
- if !ty.is_sized(ecx.tcx, ty::ParamEnv::empty()) {
+ if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty()) {
// We need to create `Allocation`s for custom DSTs
let (unsized_inner_ty, num_elems) = get_info_on_unsized_field(ty, valtree, tcx);
@@ -398,7 +398,7 @@ fn valtree_into_mplace<'tcx>(
let mut place_inner = match ty.kind() {
ty::Str | ty::Slice(_) => ecx.mplace_index(&place, i as u64).unwrap(),
- _ if !ty.is_sized(ecx.tcx, ty::ParamEnv::empty())
+ _ if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty())
&& i == branches.len() - 1 =>
{
// Note: For custom DSTs we need to manually process the last unsized field.
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index c3547cb3a..4b0550767 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -1,146 +1,146 @@
use rustc_hir::ConstContext;
-use rustc_macros::SessionDiagnostic;
+use rustc_macros::Diagnostic;
use rustc_span::Span;
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::unstable_in_stable)]
+#[derive(Diagnostic)]
+#[diag(const_eval_unstable_in_stable)]
pub(crate) struct UnstableInStable {
pub gate: String,
#[primary_span]
pub span: Span,
#[suggestion(
- const_eval::unstable_sugg,
+ unstable_sugg,
code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n",
applicability = "has-placeholders"
)]
#[suggestion(
- const_eval::bypass_sugg,
+ bypass_sugg,
code = "#[rustc_allow_const_fn_unstable({gate})]\n",
applicability = "has-placeholders"
)]
pub attr_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::thread_local_access, code = "E0625")]
+#[derive(Diagnostic)]
+#[diag(const_eval_thread_local_access, code = "E0625")]
pub(crate) struct NonConstOpErr {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::static_access, code = "E0013")]
+#[derive(Diagnostic)]
+#[diag(const_eval_static_access, code = "E0013")]
#[help]
pub(crate) struct StaticAccessErr {
#[primary_span]
pub span: Span,
pub kind: ConstContext,
- #[note(const_eval::teach_note)]
- #[help(const_eval::teach_help)]
+ #[note(teach_note)]
+ #[help(teach_help)]
pub teach: Option<()>,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::raw_ptr_to_int)]
+#[derive(Diagnostic)]
+#[diag(const_eval_raw_ptr_to_int)]
#[note]
-#[note(const_eval::note2)]
+#[note(note2)]
pub(crate) struct RawPtrToIntErr {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::raw_ptr_comparison)]
+#[derive(Diagnostic)]
+#[diag(const_eval_raw_ptr_comparison)]
#[note]
pub(crate) struct RawPtrComparisonErr {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::panic_non_str)]
+#[derive(Diagnostic)]
+#[diag(const_eval_panic_non_str)]
pub(crate) struct PanicNonStrErr {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::mut_deref, code = "E0658")]
+#[derive(Diagnostic)]
+#[diag(const_eval_mut_deref, code = "E0658")]
pub(crate) struct MutDerefErr {
#[primary_span]
pub span: Span,
pub kind: ConstContext,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::transient_mut_borrow, code = "E0658")]
+#[derive(Diagnostic)]
+#[diag(const_eval_transient_mut_borrow, code = "E0658")]
pub(crate) struct TransientMutBorrowErr {
#[primary_span]
pub span: Span,
pub kind: ConstContext,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::transient_mut_borrow_raw, code = "E0658")]
+#[derive(Diagnostic)]
+#[diag(const_eval_transient_mut_borrow_raw, code = "E0658")]
pub(crate) struct TransientMutBorrowErrRaw {
#[primary_span]
pub span: Span,
pub kind: ConstContext,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::max_num_nodes_in_const)]
+#[derive(Diagnostic)]
+#[diag(const_eval_max_num_nodes_in_const)]
pub(crate) struct MaxNumNodesInConstErr {
#[primary_span]
pub span: Span,
pub global_const_id: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::unallowed_fn_pointer_call)]
+#[derive(Diagnostic)]
+#[diag(const_eval_unallowed_fn_pointer_call)]
pub(crate) struct UnallowedFnPointerCall {
#[primary_span]
pub span: Span,
pub kind: ConstContext,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::unstable_const_fn)]
+#[derive(Diagnostic)]
+#[diag(const_eval_unstable_const_fn)]
pub(crate) struct UnstableConstFn {
#[primary_span]
pub span: Span,
pub def_path: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::unallowed_mutable_refs, code = "E0764")]
+#[derive(Diagnostic)]
+#[diag(const_eval_unallowed_mutable_refs, code = "E0764")]
pub(crate) struct UnallowedMutableRefs {
#[primary_span]
pub span: Span,
pub kind: ConstContext,
- #[note(const_eval::teach_note)]
+ #[note(teach_note)]
pub teach: Option<()>,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::unallowed_mutable_refs_raw, code = "E0764")]
+#[derive(Diagnostic)]
+#[diag(const_eval_unallowed_mutable_refs_raw, code = "E0764")]
pub(crate) struct UnallowedMutableRefsRaw {
#[primary_span]
pub span: Span,
pub kind: ConstContext,
- #[note(const_eval::teach_note)]
+ #[note(teach_note)]
pub teach: Option<()>,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::non_const_fmt_macro_call, code = "E0015")]
+#[derive(Diagnostic)]
+#[diag(const_eval_non_const_fmt_macro_call, code = "E0015")]
pub(crate) struct NonConstFmtMacroCall {
#[primary_span]
pub span: Span,
pub kind: ConstContext,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::non_const_fn_call, code = "E0015")]
+#[derive(Diagnostic)]
+#[diag(const_eval_non_const_fn_call, code = "E0015")]
pub(crate) struct NonConstFnCall {
#[primary_span]
pub span: Span,
@@ -148,35 +148,35 @@ pub(crate) struct NonConstFnCall {
pub kind: ConstContext,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::unallowed_op_in_const_context)]
+#[derive(Diagnostic)]
+#[diag(const_eval_unallowed_op_in_const_context)]
pub(crate) struct UnallowedOpInConstContext {
#[primary_span]
pub span: Span,
pub msg: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::unallowed_heap_allocations, code = "E0010")]
+#[derive(Diagnostic)]
+#[diag(const_eval_unallowed_heap_allocations, code = "E0010")]
pub(crate) struct UnallowedHeapAllocations {
#[primary_span]
#[label]
pub span: Span,
pub kind: ConstContext,
- #[note(const_eval::teach_note)]
+ #[note(teach_note)]
pub teach: Option<()>,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::unallowed_inline_asm, code = "E0015")]
+#[derive(Diagnostic)]
+#[diag(const_eval_unallowed_inline_asm, code = "E0015")]
pub(crate) struct UnallowedInlineAsm {
#[primary_span]
pub span: Span,
pub kind: ConstContext,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::interior_mutable_data_refer, code = "E0492")]
+#[derive(Diagnostic)]
+#[diag(const_eval_interior_mutable_data_refer, code = "E0492")]
pub(crate) struct InteriorMutableDataRefer {
#[primary_span]
#[label]
@@ -184,12 +184,12 @@ pub(crate) struct InteriorMutableDataRefer {
#[help]
pub opt_help: Option<()>,
pub kind: ConstContext,
- #[note(const_eval::teach_note)]
+ #[note(teach_note)]
pub teach: Option<()>,
}
-#[derive(SessionDiagnostic)]
-#[diag(const_eval::interior_mutability_borrow)]
+#[derive(Diagnostic)]
+#[diag(const_eval_interior_mutability_borrow)]
pub(crate) struct InteriorMutabilityBorrow {
#[primary_span]
pub span: Span,
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index cbe985480..269ae15d4 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -43,9 +43,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.write_immediate(res, dest)?;
}
- Misc => {
+ IntToInt | IntToFloat => {
let src = self.read_immediate(src)?;
- let res = self.misc_cast(&src, cast_ty)?;
+ let res = self.int_to_int_or_float(&src, cast_ty)?;
+ self.write_immediate(res, dest)?;
+ }
+
+ FloatToFloat | FloatToInt => {
+ let src = self.read_immediate(src)?;
+ let res = self.float_to_float_or_int(&src, cast_ty)?;
+ self.write_immediate(res, dest)?;
+ }
+
+ FnPtrToPtr | PtrToPtr => {
+ let src = self.read_immediate(&src)?;
+ let res = self.ptr_to_ptr(&src, cast_ty)?;
self.write_immediate(res, dest)?;
}
@@ -126,13 +138,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Ok(())
}
- pub fn misc_cast(
- &mut self,
+ /// Handles 'IntToInt' and 'IntToFloat' casts.
+ pub fn int_to_int_or_float(
+ &self,
+ src: &ImmTy<'tcx, M::Provenance>,
+ cast_ty: Ty<'tcx>,
+ ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
+ assert!(src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool());
+ assert!(cast_ty.is_floating_point() || cast_ty.is_integral() || cast_ty.is_char());
+
+ Ok(self.cast_from_int_like(src.to_scalar(), src.layout, cast_ty)?.into())
+ }
+
+ /// Handles 'FloatToFloat' and 'FloatToInt' casts.
+ pub fn float_to_float_or_int(
+ &self,
src: &ImmTy<'tcx, M::Provenance>,
cast_ty: Ty<'tcx>,
) -> InterpResult<'tcx, Immediate<M::Provenance>> {
use rustc_type_ir::sty::TyKind::*;
- trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty);
match src.layout.ty.kind() {
// Floating point
@@ -142,47 +166,42 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Float(FloatTy::F64) => {
return Ok(self.cast_from_float(src.to_scalar().to_f64()?, cast_ty).into());
}
- // The rest is integer/pointer-"like", including fn ptr casts
- _ => assert!(
- src.layout.ty.is_bool()
- || src.layout.ty.is_char()
- || src.layout.ty.is_integral()
- || src.layout.ty.is_any_ptr(),
- "Unexpected cast from type {:?}",
- src.layout.ty
- ),
+ _ => {
+ bug!("Can't cast 'Float' type into {:?}", cast_ty);
+ }
}
+ }
- // # First handle non-scalar source values.
-
+ /// Handles 'FnPtrToPtr' and 'PtrToPtr' casts.
+ pub fn ptr_to_ptr(
+ &self,
+ src: &ImmTy<'tcx, M::Provenance>,
+ cast_ty: Ty<'tcx>,
+ ) -> InterpResult<'tcx, Immediate<M::Provenance>> {
+ assert!(src.layout.ty.is_any_ptr());
+ assert!(cast_ty.is_unsafe_ptr());
// Handle casting any ptr to raw ptr (might be a fat ptr).
- if src.layout.ty.is_any_ptr() && cast_ty.is_unsafe_ptr() {
- let dest_layout = self.layout_of(cast_ty)?;
- if dest_layout.size == src.layout.size {
- // Thin or fat pointer that just hast the ptr kind of target type changed.
- return Ok(**src);
- } else {
- // Casting the metadata away from a fat ptr.
- assert_eq!(src.layout.size, 2 * self.pointer_size());
- assert_eq!(dest_layout.size, self.pointer_size());
- assert!(src.layout.ty.is_unsafe_ptr());
- return match **src {
- Immediate::ScalarPair(data, _) => Ok(data.into()),
- Immediate::Scalar(..) => span_bug!(
- self.cur_span(),
- "{:?} input to a fat-to-thin cast ({:?} -> {:?})",
- *src,
- src.layout.ty,
- cast_ty
- ),
- Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
- };
- }
+ let dest_layout = self.layout_of(cast_ty)?;
+ if dest_layout.size == src.layout.size {
+ // Thin or fat pointer that just hast the ptr kind of target type changed.
+ return Ok(**src);
+ } else {
+ // Casting the metadata away from a fat ptr.
+ assert_eq!(src.layout.size, 2 * self.pointer_size());
+ assert_eq!(dest_layout.size, self.pointer_size());
+ assert!(src.layout.ty.is_unsafe_ptr());
+ return match **src {
+ Immediate::ScalarPair(data, _) => Ok(data.into()),
+ Immediate::Scalar(..) => span_bug!(
+ self.cur_span(),
+ "{:?} input to a fat-to-thin cast ({:?} -> {:?})",
+ *src,
+ src.layout.ty,
+ cast_ty
+ ),
+ Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
+ };
}
-
- // # The remaining source values are scalar and "int-like".
- let scalar = src.to_scalar();
- Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
}
pub fn pointer_expose_address_cast(
@@ -203,7 +222,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
pub fn pointer_from_exposed_address_cast(
- &mut self,
+ &self,
src: &ImmTy<'tcx, M::Provenance>,
cast_ty: Ty<'tcx>,
) -> InterpResult<'tcx, Immediate<M::Provenance>> {
@@ -220,6 +239,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Ok(Scalar::from_maybe_pointer(ptr, self).into())
}
+ /// Low-level cast helper function. This works directly on scalars and can take 'int-like' input
+ /// type (basically everything with a scalar layout) to int/float/char types.
pub fn cast_from_int_like(
&self,
scalar: Scalar<M::Provenance>, // input value (there is no ScalarTy so we separate data+layout)
@@ -259,6 +280,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
})
}
+ /// Low-level cast helper function. Converts an apfloat `f` into int or float types.
fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::Provenance>
where
F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>,
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index d37eaeed0..a9063ad31 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -258,6 +258,9 @@ impl<'tcx> fmt::Display for FrameInfo<'tcx> {
{
write!(f, "inside closure")?;
} else {
+ // Note: this triggers a `good_path_bug` state, which means that if we ever get here
+ // we must emit a diagnostic. We should never display a `FrameInfo` unless we
+ // actually want to emit a warning or error to the user.
write!(f, "inside `{}`", self.instance)?;
}
if !self.span.is_dummy() {
@@ -465,7 +468,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
#[inline]
pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
- ty.is_freeze(self.tcx, self.param_env)
+ ty.is_freeze(*self.tcx, self.param_env)
}
pub fn load_mir(
@@ -683,11 +686,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.stack_mut().push(frame);
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
- for const_ in &body.required_consts {
- let span = const_.span;
- let const_ =
- self.subst_from_current_frame_and_normalize_erasing_regions(const_.literal)?;
- self.mir_const_to_op(&const_, None).map_err(|err| {
+ for ct in &body.required_consts {
+ let span = ct.span;
+ let ct = self.subst_from_current_frame_and_normalize_erasing_regions(ct.literal)?;
+ self.const_to_op(&ct, None).map_err(|err| {
// If there was an error, set the span of the current frame to this constant.
// Avoiding doing this when evaluation succeeds.
self.frame_mut().loc = Err(span);
@@ -929,11 +931,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
#[must_use]
- pub fn generate_stacktrace(&self) -> Vec<FrameInfo<'tcx>> {
+ pub fn generate_stacktrace_from_stack(
+ stack: &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>],
+ ) -> Vec<FrameInfo<'tcx>> {
let mut frames = Vec::new();
// This deliberately does *not* honor `requires_caller_location` since it is used for much
// more than just panics.
- for frame in self.stack().iter().rev() {
+ for frame in stack.iter().rev() {
let lint_root = frame.current_source_info().and_then(|source_info| {
match &frame.body.source_scopes[source_info.scope].local_data {
mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
@@ -947,6 +951,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
trace!("generate stacktrace: {:#?}", frames);
frames
}
+
+ #[must_use]
+ pub fn generate_stacktrace(&self) -> Vec<FrameInfo<'tcx>> {
+ Self::generate_stacktrace_from_stack(self.stack())
+ }
}
#[doc(hidden)]
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 24dbc7695..6809a42dc 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -15,7 +15,7 @@
//! that contains allocations whose mutability we cannot identify.)
use super::validity::RefTracking;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_middle::mir::interpret::InterpResult;
@@ -37,7 +37,7 @@ pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine<
ExtraFnVal = !,
FrameExtra = (),
AllocExtra = (),
- MemoryMap = FxHashMap<AllocId, (MemoryKind<T>, Allocation)>,
+ MemoryMap = FxIndexMap<AllocId, (MemoryKind<T>, Allocation)>,
>;
struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> {
@@ -47,7 +47,7 @@ struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_ev
ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, InternMode)>,
/// A list of all encountered allocations. After type-based interning, we traverse this list to
/// also intern allocations that are only referenced by a raw pointer or inside a union.
- leftover_allocations: &'rt mut FxHashSet<AllocId>,
+ leftover_allocations: &'rt mut FxIndexSet<AllocId>,
/// The root kind of the value that we're looking at. This field is never mutated for a
/// particular allocation. It is primarily used to make as many allocations as possible
/// read-only so LLVM can place them in const memory.
@@ -79,7 +79,7 @@ struct IsStaticOrFn;
/// to account for (e.g. for vtables).
fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>(
ecx: &'rt mut InterpCx<'mir, 'tcx, M>,
- leftover_allocations: &'rt mut FxHashSet<AllocId>,
+ leftover_allocations: &'rt mut FxIndexSet<AllocId>,
alloc_id: AllocId,
mode: InternMode,
ty: Option<Ty<'tcx>>,
@@ -114,7 +114,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval:
if let InternMode::Static(mutability) = mode {
// For this, we need to take into account `UnsafeCell`. When `ty` is `None`, we assume
// no interior mutability.
- let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx, ecx.param_env));
+ let frozen = ty.map_or(true, |ty| ty.is_freeze(*ecx.tcx, ecx.param_env));
// For statics, allocation mutability is the combination of place mutability and
// type mutability.
// The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere.
@@ -332,8 +332,6 @@ pub enum InternKind {
///
/// This *cannot raise an interpreter error*. Doing so is left to validation, which
/// tracks where in the value we are and thus can show much better error messages.
-/// Any errors here would anyway be turned into `const_err` lints, whereas validation failures
-/// are hard errors.
#[instrument(level = "debug", skip(ecx))]
pub fn intern_const_alloc_recursive<
'mir,
@@ -357,7 +355,7 @@ pub fn intern_const_alloc_recursive<
// `leftover_allocations` collects *all* allocations we see, because some might not
// be available in a typed way. They get interned at the end.
let mut ref_tracking = RefTracking::empty();
- let leftover_allocations = &mut FxHashSet::default();
+ let leftover_allocations = &mut FxIndexSet::default();
// start with the outermost allocation
intern_shallow(
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 91f4f0425..0e3867557 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
@@ -4,7 +4,6 @@ use rustc_ast::Mutability;
use rustc_hir::lang_items::LangItem;
use rustc_middle::mir::TerminatorKind;
use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::subst::Subst;
use rustc_span::{Span, Symbol};
use crate::interpret::{
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
index 7e4c5fcb0..ffdb8de5b 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
@@ -4,7 +4,7 @@ use rustc_hir::definitions::DisambiguatedDefPathData;
use rustc_middle::mir::interpret::{Allocation, ConstAllocation};
use rustc_middle::ty::{
self,
- print::{PrettyPrinter, Print, Printer},
+ print::{with_no_verbose_constants, PrettyPrinter, Print, Printer},
subst::{GenericArg, GenericArgKind},
Ty, TyCtxt,
};
@@ -190,7 +190,9 @@ impl Write for AbsolutePathPrinter<'_> {
/// Directly returns an `Allocation` containing an absolute path representation of the given type.
pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> {
- let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
+ let path = with_no_verbose_constants!(
+ AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path
+ );
let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes());
tcx.intern_const_alloc(alloc)
}
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 530e252b7..351152eba 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -426,7 +426,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
type ExtraFnVal = !;
type MemoryMap =
- rustc_data_structures::fx::FxHashMap<AllocId, (MemoryKind<Self::MemoryKind>, Allocation)>;
+ rustc_data_structures::fx::FxIndexMap<AllocId, (MemoryKind<Self::MemoryKind>, Allocation)>;
const GLOBAL_KIND: Option<Self::MemoryKind> = None; // no copying of globals from `tcx` to machine memory
type AllocExtra = ();
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index ed155fbfe..e5e015c1e 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -794,7 +794,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
todo.extend(static_roots);
while let Some(id) = todo.pop() {
if reachable.insert(id) {
- // This is a new allocation, add the allocation it points to to `todo`.
+ // This is a new allocation, add the allocation it points to `todo`.
if let Some((_, alloc)) = self.memory.alloc_map.get(id) {
todo.extend(
alloc.provenance().values().filter_map(|prov| prov.get_alloc_id()),
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 0e3959b61..0c212cf59 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -534,7 +534,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// * During ConstProp, with `TooGeneric` or since the `required_consts` were not all
// checked yet.
// * During CTFE, since promoteds in `const`/`static` initializer bodies can fail.
- self.mir_const_to_op(&val, layout)?
+ self.const_to_op(&val, layout)?
}
};
trace!("{:?}: {:?}", mir_op, *op);
@@ -549,45 +549,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
ops.iter().map(|op| self.eval_operand(op, None)).collect()
}
- // Used when the miri-engine runs into a constant and for extracting information from constants
- // in patterns via the `const_eval` module
- /// The `val` and `layout` are assumed to already be in our interpreter
- /// "universe" (param_env).
pub fn const_to_op(
&self,
- c: ty::Const<'tcx>,
- layout: Option<TyAndLayout<'tcx>>,
- ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
- match c.kind() {
- ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(..) => throw_inval!(TooGeneric),
- ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => {
- throw_inval!(AlreadyReported(reported))
- }
- ty::ConstKind::Unevaluated(uv) => {
- // NOTE: We evaluate to a `ValTree` here as a check to ensure
- // we're working with valid constants, even though we never need it.
- let instance = self.resolve(uv.def, uv.substs)?;
- let cid = GlobalId { instance, promoted: None };
- let _valtree = self
- .tcx
- .eval_to_valtree(self.param_env.and(cid))?
- .unwrap_or_else(|| bug!("unable to create ValTree for {:?}", uv));
-
- Ok(self.eval_to_allocation(cid)?.into())
- }
- ty::ConstKind::Bound(..) | ty::ConstKind::Infer(..) => {
- span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", c)
- }
- ty::ConstKind::Value(valtree) => {
- let ty = c.ty();
- let const_val = self.tcx.valtree_to_const_val((ty, valtree));
- self.const_val_to_op(const_val, ty, layout)
- }
- }
- }
-
- pub fn mir_const_to_op(
- &self,
val: &mir::ConstantKind<'tcx>,
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
@@ -599,7 +562,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// manually normalized.
let val = self.tcx.normalize_erasing_regions(self.param_env, *val);
match val {
- mir::ConstantKind::Ty(ct) => self.const_to_op(ct, layout),
+ mir::ConstantKind::Ty(ct) => {
+ match ct.kind() {
+ ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(..) => {
+ throw_inval!(TooGeneric)
+ }
+ ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => {
+ throw_inval!(AlreadyReported(reported))
+ }
+ ty::ConstKind::Unevaluated(uv) => {
+ // NOTE: We evaluate to a `ValTree` here as a check to ensure
+ // we're working with valid constants, even though we never need it.
+ let instance = self.resolve(uv.def, uv.substs)?;
+ let cid = GlobalId { instance, promoted: None };
+ let _valtree = self
+ .tcx
+ .eval_to_valtree(self.param_env.and(cid))?
+ .unwrap_or_else(|| bug!("unable to create ValTree for {uv:?}"));
+
+ Ok(self.eval_to_allocation(cid)?.into())
+ }
+ ty::ConstKind::Bound(..) | ty::ConstKind::Infer(..) => {
+ span_bug!(self.cur_span(), "unexpected ConstKind in ctfe: {ct:?}")
+ }
+ ty::ConstKind::Value(valtree) => {
+ let ty = ct.ty();
+ let const_val = self.tcx.valtree_to_const_val((ty, valtree));
+ self.const_val_to_op(const_val, ty, layout)
+ }
+ }
+ }
mir::ConstantKind::Val(val, ty) => self.const_val_to_op(val, ty, layout),
mir::ConstantKind::Unevaluated(uv, _) => {
let instance = self.resolve(uv.def, uv.substs)?;
@@ -799,13 +791,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64", not(bootstrap)))]
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;
- // These are in alphabetical order, which is easy to maintain.
+ // tidy-alphabetical-start
static_assert_size!(Immediate, 48);
static_assert_size!(ImmTy<'_>, 64);
static_assert_size!(Operand, 56);
static_assert_size!(OpTy<'_>, 80);
+ // tidy-alphabetical-end
}
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index b32889290..b0625b5f4 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -280,7 +280,7 @@ impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> {
#[inline(always)]
#[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
- pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Prov> {
+ pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Prov> {
self.try_as_mplace().unwrap()
}
}
@@ -640,11 +640,17 @@ where
// avoid force_allocation.
let src = match self.read_immediate_raw(src)? {
Ok(src_val) => {
- assert!(!src.layout.is_unsized(), "cannot copy unsized immediates");
- assert!(
- !dest.layout.is_unsized(),
- "the src is sized, so the dest must also be sized"
- );
+ // FIXME(const_prop): Const-prop can possibly evaluate an
+ // unsized copy operation when it thinks that the type is
+ // actually sized, due to a trivially false where-clause
+ // predicate like `where Self: Sized` with `Self = dyn Trait`.
+ // See #102553 for an example of such a predicate.
+ if src.layout.is_unsized() {
+ throw_inval!(SizeOfUnsizedType(src.layout.ty));
+ }
+ if dest.layout.is_unsized() {
+ throw_inval!(SizeOfUnsizedType(dest.layout.ty));
+ }
assert_eq!(src.layout.size, dest.layout.size);
// Yay, we got a value that we can write directly.
return if layout_compat {
@@ -886,12 +892,11 @@ where
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;
- // These are in alphabetical order, which is easy to maintain.
- static_assert_size!(MemPlaceMeta, 24);
+ // tidy-alphabetical-start
static_assert_size!(MemPlace, 40);
+ static_assert_size!(MemPlaceMeta, 24);
static_assert_size!(MPlaceTy<'_>, 64);
- #[cfg(not(bootstrap))]
static_assert_size!(Place, 40);
- #[cfg(not(bootstrap))]
static_assert_size!(PlaceTy<'_>, 64);
+ // tidy-alphabetical-end
}
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index 77da8f104..6b2e2bb8a 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -350,6 +350,11 @@ where
) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
use rustc_middle::mir::ProjectionElem::*;
Ok(match proj_elem {
+ OpaqueCast(ty) => {
+ let mut place = base.clone();
+ place.layout = self.layout_of(ty)?;
+ place
+ }
Field(field, _) => self.place_field(base, field.index())?,
Downcast(_, variant) => self.place_downcast(base, variant)?,
Deref => self.deref_operand(&self.place_to_op(base)?)?.into(),
@@ -374,6 +379,11 @@ where
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
use rustc_middle::mir::ProjectionElem::*;
Ok(match proj_elem {
+ OpaqueCast(ty) => {
+ let mut op = base.clone();
+ op.layout = self.layout_of(ty)?;
+ op
+ }
Field(field, _) => self.operand_field(base, field.index())?,
Downcast(_, variant) => self.operand_downcast(base, variant)?,
Deref => self.deref_operand(base)?.into(),
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 50a82aa0e..57e40e168 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -35,7 +35,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
assert_eq!(discr.layout.ty, switch_ty);
// Branch to the `otherwise` case by default, if no match is found.
- assert!(!targets.iter().is_empty());
let mut target_block = targets.otherwise();
for (const_int, target) in targets.iter() {
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 14aaee6ac..8aa56c275 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -15,7 +15,6 @@ use rustc_middle::mir::interpret::InterpError;
use rustc_middle::ty;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_span::symbol::{sym, Symbol};
-use rustc_span::DUMMY_SP;
use rustc_target::abi::{Abi, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange};
use std::hash::Hash;
@@ -56,7 +55,7 @@ macro_rules! throw_validation_failure {
/// This lets you use the patterns as a kind of validation list, asserting which errors
/// can possibly happen:
///
-/// ```
+/// ```ignore(illustrative)
/// let v = try_validation!(some_fn(), some_path, {
/// Foo | Bar | Baz => { "some failure" },
/// });
@@ -65,7 +64,7 @@ macro_rules! throw_validation_failure {
/// The patterns must be of type `UndefinedBehaviorInfo`.
/// An additional expected parameter can also be added to the failure message:
///
-/// ```
+/// ```ignore(illustrative)
/// let v = try_validation!(some_fn(), some_path, {
/// Foo | Bar | Baz => { "some failure" } expected { "something that wasn't a failure" },
/// });
@@ -74,7 +73,7 @@ macro_rules! throw_validation_failure {
/// An additional nicety is that both parameters actually take format args, so you can just write
/// the format string in directly:
///
-/// ```
+/// ```ignore(illustrative)
/// let v = try_validation!(some_fn(), some_path, {
/// Foo | Bar | Baz => { "{:?}", some_failure } expected { "{}", expected_value },
/// });
@@ -726,7 +725,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
) -> InterpResult<'tcx> {
// Special check preventing `UnsafeCell` inside unions in the inner part of constants.
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) {
- if !op.layout.ty.is_freeze(self.ecx.tcx.at(DUMMY_SP), self.ecx.param_env) {
+ if !op.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.param_env) {
throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" });
}
}
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 9f47d302a..443c01fdb 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -10,7 +10,6 @@ Rust MIR: a lowered representation of Rust.
#![feature(decl_macro)]
#![feature(exact_size_is_empty)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(map_try_insert)]
#![feature(min_specialization)]
#![feature(slice_ptr_get)]
@@ -21,9 +20,8 @@ Rust MIR: a lowered representation of Rust.
#![feature(trusted_step)]
#![feature(try_blocks)]
#![feature(yeet_expr)]
-#![feature(is_some_with)]
+#![feature(is_some_and)]
#![recursion_limit = "256"]
-#![allow(rustc::potential_query_instability)]
#[macro_use]
extern crate tracing;
@@ -33,7 +31,6 @@ extern crate rustc_middle;
pub mod const_eval;
mod errors;
pub mod interpret;
-mod might_permit_raw_init;
pub mod transform;
pub mod util;
@@ -62,7 +59,6 @@ pub fn provide(providers: &mut Providers) {
const_eval::deref_mir_constant(tcx, param_env, value)
};
providers.permits_uninit_init =
- |tcx, ty| might_permit_raw_init::might_permit_raw_init(tcx, ty, InitKind::Uninit);
- providers.permits_zero_init =
- |tcx, ty| might_permit_raw_init::might_permit_raw_init(tcx, ty, InitKind::Zero);
+ |tcx, ty| util::might_permit_raw_init(tcx, ty, InitKind::UninitMitigated0x01Fill);
+ providers.permits_zero_init = |tcx, ty| util::might_permit_raw_init(tcx, ty, InitKind::Zero);
}
diff --git a/compiler/rustc_const_eval/src/might_permit_raw_init.rs b/compiler/rustc_const_eval/src/might_permit_raw_init.rs
deleted file mode 100644
index 37ffa19cc..000000000
--- a/compiler/rustc_const_eval/src/might_permit_raw_init.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-use crate::const_eval::CompileTimeInterpreter;
-use crate::interpret::{InterpCx, MemoryKind, OpTy};
-use rustc_middle::ty::layout::LayoutCx;
-use rustc_middle::ty::{layout::TyAndLayout, ParamEnv, TyCtxt};
-use rustc_session::Limit;
-use rustc_target::abi::InitKind;
-
-pub fn might_permit_raw_init<'tcx>(
- tcx: TyCtxt<'tcx>,
- ty: TyAndLayout<'tcx>,
- kind: InitKind,
-) -> bool {
- let strict = tcx.sess.opts.unstable_opts.strict_init_checks;
-
- if strict {
- let machine = CompileTimeInterpreter::new(
- Limit::new(0),
- /*can_access_statics:*/ false,
- /*check_alignment:*/ true,
- );
-
- let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
-
- let allocated = cx
- .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
- .expect("OOM: failed to allocate for uninit check");
-
- if kind == InitKind::Zero {
- cx.write_bytes_ptr(
- allocated.ptr,
- std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()),
- )
- .expect("failed to write bytes for zero valid check");
- }
-
- let ot: OpTy<'_, _> = allocated.into();
-
- // Assume that if it failed, it's a validation failure.
- cx.validate_operand(&ot).is_ok()
- } else {
- let layout_cx = LayoutCx { tcx, param_env: ParamEnv::reveal_all() };
- ty.might_permit_raw_init(&layout_cx, kind)
- }
-}
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 7e15858c8..22a61774e 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -13,8 +13,11 @@ use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty,
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeVisitable};
use rustc_mir_dataflow::{self, Analysis};
use rustc_span::{sym, Span, Symbol};
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
-use rustc_trait_selection::traits::SelectionContext;
+use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
+use rustc_trait_selection::traits::{
+ self, ObligationCauseCode, SelectionContext, TraitEngine, TraitEngineExt,
+};
use std::mem;
use std::ops::Deref;
@@ -550,7 +553,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
unimplemented!()
}
- Rvalue::Cast(CastKind::Misc, _, _) => {}
+ Rvalue::Cast(_, _, _) => {}
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
Rvalue::ShallowInitBox(_, _) => {}
@@ -656,6 +659,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Downcast(..)
+ | ProjectionElem::OpaqueCast(..)
| ProjectionElem::Subslice { .. }
| ProjectionElem::Field(..)
| ProjectionElem::Index(_) => {}
@@ -733,10 +737,49 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
let obligation =
Obligation::new(ObligationCause::dummy(), param_env, poly_trait_pred);
- let implsrc = tcx.infer_ctxt().enter(|infcx| {
+ let implsrc = {
+ let infcx = tcx.infer_ctxt().build();
let mut selcx = SelectionContext::new(&infcx);
selcx.select(&obligation)
- });
+ };
+
+ // do a well-formedness check on the trait method being called. This is because typeck only does a
+ // "non-const" check. This is required for correctness here.
+ {
+ let infcx = tcx.infer_ctxt().build();
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+ let predicates = tcx.predicates_of(callee).instantiate(tcx, substs);
+ let hir_id = tcx
+ .hir()
+ .local_def_id_to_hir_id(self.body.source.def_id().expect_local());
+ let cause = || {
+ ObligationCause::new(
+ terminator.source_info.span,
+ hir_id,
+ ObligationCauseCode::ItemObligation(callee),
+ )
+ };
+ let normalized = infcx.partially_normalize_associated_types_in(
+ cause(),
+ param_env,
+ predicates,
+ );
+
+ for p in normalized.obligations {
+ fulfill_cx.register_predicate_obligation(&infcx, p);
+ }
+ for obligation in traits::predicates_for_generics(
+ |_, _| cause(),
+ self.param_env,
+ normalized.value,
+ ) {
+ fulfill_cx.register_predicate_obligation(&infcx, obligation);
+ }
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ }
+ }
match implsrc {
Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
@@ -794,16 +837,15 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// improve diagnostics by showing what failed. Our requirements are stricter this time
// as we are going to error again anyways.
- tcx.infer_ctxt().enter(|infcx| {
- if let Err(e) = implsrc {
- infcx.report_selection_error(
- obligation.clone(),
- &obligation,
- &e,
- false,
- );
- }
- });
+ let infcx = tcx.infer_ctxt().build();
+ if let Err(e) = implsrc {
+ infcx.err_ctxt().report_selection_error(
+ obligation.clone(),
+ &obligation,
+ &e,
+ false,
+ );
+ }
self.check_op(ops::FnCallNonConst {
caller,
@@ -867,8 +909,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
return;
}
- let is_intrinsic = tcx.is_intrinsic(callee);
-
if !tcx.is_const_fn_raw(callee) {
if !tcx.is_const_default_method(callee) {
// To get to here we must have already found a const impl for the
@@ -928,7 +968,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// We do not use `const` modifiers for intrinsic "functions", as intrinsics are
// `extern` functions, and these have no way to get marked `const`. So instead we
// use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const`
- if self.ccx.is_const_stable_const_fn() || is_intrinsic {
+ if self.ccx.is_const_stable_const_fn() || tcx.is_intrinsic(callee) {
self.check_op(ops::FnCallUnstable(callee, None));
return;
}
@@ -968,7 +1008,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
if needs_non_const_drop {
self.check_op_spanned(
- ops::LiveDrop { dropped_at: Some(terminator.source_info.span) },
+ ops::LiveDrop {
+ dropped_at: Some(terminator.source_info.span),
+ dropped_ty: ty_of_dropped_place,
+ },
err_span,
);
}
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 5fb4bf638..b28d70194 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -156,10 +156,9 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
}),
);
- let implsrc = tcx.infer_ctxt().enter(|infcx| {
- let mut selcx = SelectionContext::new(&infcx);
- selcx.select(&obligation)
- });
+ let infcx = tcx.infer_ctxt().build();
+ let mut selcx = SelectionContext::new(&infcx);
+ let implsrc = selcx.select(&obligation);
if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
let span = tcx.def_span(data.impl_def_id);
@@ -422,10 +421,11 @@ impl<'tcx> NonConstOp<'tcx> for InlineAsm {
}
#[derive(Debug)]
-pub struct LiveDrop {
+pub struct LiveDrop<'tcx> {
pub dropped_at: Option<Span>,
+ pub dropped_ty: Ty<'tcx>,
}
-impl<'tcx> NonConstOp<'tcx> for LiveDrop {
+impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> {
fn build_error(
&self,
ccx: &ConstCx<'_, 'tcx>,
@@ -435,9 +435,13 @@ impl<'tcx> NonConstOp<'tcx> for LiveDrop {
ccx.tcx.sess,
span,
E0493,
- "destructors cannot be evaluated at compile-time"
+ "destructor of `{}` cannot be evaluated at compile-time",
+ self.dropped_ty,
+ );
+ err.span_label(
+ span,
+ format!("the destructor for this type cannot be evaluated in {}s", ccx.const_kind()),
);
- err.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()));
if let Some(span) = self.dropped_at {
err.span_label(span, "value is dropped here");
}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
index 4e210f663..d4570c598 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
@@ -1,6 +1,6 @@
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{self, BasicBlock, Location};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{Ty, TyCtxt};
use rustc_span::{symbol::sym, Span};
use super::check::Qualifs;
@@ -58,9 +58,9 @@ impl<'mir, 'tcx> std::ops::Deref for CheckLiveDrops<'mir, 'tcx> {
}
}
-impl CheckLiveDrops<'_, '_> {
- fn check_live_drop(&self, span: Span) {
- ops::LiveDrop { dropped_at: None }.build_error(self.ccx, span).emit();
+impl<'tcx> CheckLiveDrops<'_, 'tcx> {
+ fn check_live_drop(&self, span: Span, dropped_ty: Ty<'tcx>) {
+ ops::LiveDrop { dropped_at: None, dropped_ty }.build_error(self.ccx, span).emit();
}
}
@@ -90,7 +90,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
}
if dropped_place.is_indirect() {
- self.check_live_drop(terminator.source_info.span);
+ self.check_live_drop(terminator.source_info.span, dropped_ty);
return;
}
@@ -101,7 +101,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
if self.qualifs.needs_non_const_drop(self.ccx, dropped_place.local, location) {
// Use the span where the dropped local was declared for the error.
let span = self.body.local_decls[dropped_place.local].source_info.span;
- self.check_live_drop(span);
+ self.check_live_drop(span, dropped_ty);
}
}
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 6c73ef5a8..335992342 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -5,9 +5,9 @@
use rustc_errors::ErrorGuaranteed;
use rustc_hir::LangItem;
use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::mir;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
-use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits::{
self, ImplSource, Obligation, ObligationCause, SelectionContext,
};
@@ -91,7 +91,7 @@ impl Qualif for HasMutInterior {
}
fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
- !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env)
+ !ty.is_freeze(cx.tcx, cx.param_env)
}
fn in_adt_inherently<'tcx>(
@@ -167,30 +167,28 @@ impl Qualif for NeedsNonConstDrop {
}),
);
- cx.tcx.infer_ctxt().enter(|infcx| {
- let mut selcx = SelectionContext::new(&infcx);
- let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
- // If we couldn't select a const destruct candidate, then it's bad
- return true;
- };
-
- if !matches!(
- impl_src,
- ImplSource::ConstDestruct(_)
- | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
- ) {
- // If our const destruct candidate is not ConstDestruct or implied by the param env,
- // then it's bad
- return true;
- }
+ let infcx = cx.tcx.infer_ctxt().build();
+ let mut selcx = SelectionContext::new(&infcx);
+ let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
+ // If we couldn't select a const destruct candidate, then it's bad
+ return true;
+ };
+
+ if !matches!(
+ impl_src,
+ ImplSource::ConstDestruct(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
+ ) {
+ // If our const destruct candidate is not ConstDestruct or implied by the param env,
+ // then it's bad
+ return true;
+ }
- if impl_src.borrow_nested_obligations().is_empty() {
- return false;
- }
+ if impl_src.borrow_nested_obligations().is_empty() {
+ return false;
+ }
- // If we had any errors, then it's bad
- !traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty()
- })
+ // If we had any errors, then it's bad
+ !traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty()
}
fn in_adt_inherently<'tcx>(
@@ -308,6 +306,7 @@ where
ProjectionElem::Deref
| ProjectionElem::Field(_, _)
+ | ProjectionElem::OpaqueCast(_)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(_, _)
@@ -349,17 +348,13 @@ where
// FIXME(valtrees): check whether const qualifs should behave the same
// way for type and mir constants.
let uneval = match constant.literal {
- ConstantKind::Ty(ct) if matches!(ct.kind(), ty::ConstKind::Unevaluated(_)) => {
- let ty::ConstKind::Unevaluated(uv) = ct.kind() else { unreachable!() };
-
- Some(uv.expand())
- }
- ConstantKind::Ty(_) => None,
+ ConstantKind::Ty(ct) if matches!(ct.kind(), ty::ConstKind::Param(_)) => None,
+ ConstantKind::Ty(c) => bug!("expected ConstKind::Param here, found {:?}", c),
ConstantKind::Unevaluated(uv, _) => Some(uv),
ConstantKind::Val(..) => None,
};
- if let Some(ty::Unevaluated { def, substs: _, promoted }) = uneval {
+ if let Some(mir::UnevaluatedConst { def, substs: _, promoted }) = uneval {
// Use qualifs of the type for the promoted. Promoteds in MIR body should be possible
// only for `NeedsNonConstDrop` with precise drop checking. This is the only const
// check performed after the promotion. Verify that with an assertion.
@@ -367,11 +362,8 @@ where
// Don't peek inside trait associated constants.
if promoted.is_none() && cx.tcx.trait_of_item(def.did).is_none() {
- let qualifs = if let Some((did, param_did)) = def.as_const_arg() {
- cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did))
- } else {
- cx.tcx.at(constant.span).mir_const_qualif(def.did)
- };
+ assert_eq!(def.const_param_did, None, "expected associated const: {def:?}");
+ let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def.did);
if !Q::in_qualifs(&qualifs) {
return false;
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index 60c1e4950..805e6096b 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -8,7 +8,6 @@ use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementK
use rustc_mir_dataflow::fmt::DebugWithContext;
use rustc_mir_dataflow::JoinSemiLattice;
use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces};
-use rustc_span::DUMMY_SP;
use std::fmt;
use std::marker::PhantomData;
@@ -120,10 +119,7 @@ where
///
/// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool {
- !place
- .ty(self.ccx.body, self.ccx.tcx)
- .ty
- .is_freeze(self.ccx.tcx.at(DUMMY_SP), self.ccx.param_env)
+ !place.ty(self.ccx.body, self.ccx.tcx).ty.is_freeze(self.ccx.tcx, self.ccx.param_env)
}
}
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index f7a7cc88a..f3ae16da4 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -13,6 +13,7 @@
//! move analysis runs after promotion on broken MIR.
use rustc_hir as hir;
+use rustc_middle::mir;
use rustc_middle::mir::traversal::ReversePostorderIter;
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
@@ -40,10 +41,6 @@ pub struct PromoteTemps<'tcx> {
}
impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
- fn phase_change(&self) -> Option<MirPhase> {
- Some(MirPhase::Analysis(AnalysisPhase::Initial))
- }
-
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// There's not really any point in promoting errorful MIR.
//
@@ -361,7 +358,7 @@ impl<'tcx> Validator<'_, 'tcx> {
return Err(Unpromotable);
}
}
- ProjectionElem::Downcast(..) => {
+ ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => {
return Err(Unpromotable);
}
@@ -840,7 +837,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
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 uneval = ty::Unevaluated { def, substs, promoted: Some(promoted_id) };
+ let uneval = mir::UnevaluatedConst { def, substs, promoted: Some(promoted_id) };
Operand::Constant(Box::new(Constant {
span,
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 4aa98cb13..81b82a21f 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -13,7 +13,6 @@ use rustc_middle::mir::{
TerminatorKind, UnOp, START_BLOCK,
};
use rustc_middle::ty::fold::BottomUpFolder;
-use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable, TypeVisitable};
use rustc_mir_dataflow::impls::MaybeStorageLive;
use rustc_mir_dataflow::storage::always_storage_live_locals;
@@ -106,7 +105,7 @@ pub fn equal_up_to_regions<'tcx>(
},
)
};
- tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok())
+ tcx.infer_ctxt().build().can_eq(param_env, normalize(src), normalize(dest)).is_ok()
}
struct TypeChecker<'a, 'tcx> {
@@ -236,9 +235,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
// `Operand::Copy` is only supposed to be used with `Copy` types.
if let Operand::Copy(place) = operand {
let ty = place.ty(&self.body.local_decls, self.tcx).ty;
- let span = self.body.source_info(location).span;
- if !ty.is_copy_modulo_regions(self.tcx.at(span), self.param_env) {
+ if !ty.is_copy_modulo_regions(self.tcx, self.param_env) {
self.fail(location, format!("`Operand::Copy` with non-`Copy` type {}", ty));
}
}
@@ -285,7 +283,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
this.fail(
location,
format!(
- "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is {:?}",
+ "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is `{:?}`",
parent, f, ty, f_ty
)
)
@@ -557,25 +555,40 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
check_kinds!(a, "Cannot shallow init type {:?}", ty::RawPtr(..));
}
Rvalue::Cast(kind, operand, target_type) => {
+ let op_ty = operand.ty(self.body, self.tcx);
match kind {
- CastKind::Misc => {
- let op_ty = operand.ty(self.body, self.tcx);
- if op_ty.is_enum() {
+ CastKind::DynStar => {
+ // FIXME(dyn-star): make sure nothing needs to be done here.
+ }
+ // FIXME: Add Checks for these
+ CastKind::PointerFromExposedAddress
+ | CastKind::PointerExposeAddress
+ | CastKind::Pointer(_) => {}
+ CastKind::IntToInt | CastKind::IntToFloat => {
+ let input_valid = op_ty.is_integral() || op_ty.is_char() || op_ty.is_bool();
+ let target_valid = target_type.is_numeric() || target_type.is_char();
+ if !input_valid || !target_valid {
+ self.fail(
+ location,
+ format!("Wrong cast kind {kind:?} for the type {op_ty}",),
+ );
+ }
+ }
+ CastKind::FnPtrToPtr | CastKind::PtrToPtr => {
+ if !(op_ty.is_any_ptr() && target_type.is_unsafe_ptr()) {
+ self.fail(location, "Can't cast {op_ty} into 'Ptr'");
+ }
+ }
+ CastKind::FloatToFloat | CastKind::FloatToInt => {
+ if !op_ty.is_floating_point() || !target_type.is_numeric() {
self.fail(
location,
format!(
- "enum -> int casts should go through `Rvalue::Discriminant`: {operand:?}:{op_ty} as {target_type}",
+ "Trying to cast non 'Float' as {kind:?} into {target_type:?}"
),
);
}
}
- CastKind::DynStar => {
- // FIXME(dyn-star): make sure nothing needs to be done here.
- }
- // Nothing to check here
- CastKind::PointerFromExposedAddress
- | CastKind::PointerExposeAddress
- | CastKind::Pointer(_) => {}
}
}
Rvalue::Repeat(_, _)
diff --git a/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs b/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
new file mode 100644
index 000000000..6ca712233
--- /dev/null
+++ b/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
@@ -0,0 +1,151 @@
+use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
+use rustc_middle::ty::{ParamEnv, TyCtxt};
+use rustc_session::Limit;
+use rustc_target::abi::{Abi, FieldsShape, InitKind, Scalar, Variants};
+
+use crate::const_eval::CompileTimeInterpreter;
+use crate::interpret::{InterpCx, MemoryKind, OpTy};
+
+/// Determines if this type permits "raw" initialization by just transmuting some memory into an
+/// instance of `T`.
+///
+/// `init_kind` indicates if the memory is zero-initialized or left uninitialized. We assume
+/// uninitialized memory is mitigated by filling it with 0x01, which reduces the chance of causing
+/// LLVM UB.
+///
+/// By default we check whether that operation would cause *LLVM UB*, i.e., whether the LLVM IR we
+/// generate has UB or not. This is a mitigation strategy, which is why we are okay with accepting
+/// Rust UB as long as there is no risk of miscompilations. The `strict_init_checks` can be set to
+/// do a full check against Rust UB instead (in which case we will also ignore the 0x01-filling and
+/// to the full uninit check).
+pub fn might_permit_raw_init<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ty: TyAndLayout<'tcx>,
+ kind: InitKind,
+) -> bool {
+ if tcx.sess.opts.unstable_opts.strict_init_checks {
+ might_permit_raw_init_strict(ty, tcx, kind)
+ } else {
+ let layout_cx = LayoutCx { tcx, param_env: ParamEnv::reveal_all() };
+ might_permit_raw_init_lax(ty, &layout_cx, kind)
+ }
+}
+
+/// Implements the 'strict' version of the `might_permit_raw_init` checks; see that function for
+/// details.
+fn might_permit_raw_init_strict<'tcx>(
+ ty: TyAndLayout<'tcx>,
+ tcx: TyCtxt<'tcx>,
+ kind: InitKind,
+) -> bool {
+ let machine = CompileTimeInterpreter::new(
+ Limit::new(0),
+ /*can_access_statics:*/ false,
+ /*check_alignment:*/ true,
+ );
+
+ let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
+
+ let allocated = cx
+ .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
+ .expect("OOM: failed to allocate for uninit check");
+
+ if kind == InitKind::Zero {
+ cx.write_bytes_ptr(
+ allocated.ptr,
+ std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()),
+ )
+ .expect("failed to write bytes for zero valid check");
+ }
+
+ let ot: OpTy<'_, _> = allocated.into();
+
+ // Assume that if it failed, it's a validation failure.
+ // This does *not* actually check that references are dereferenceable, but since all types that
+ // require dereferenceability also require non-null, we don't actually get any false negatives
+ // due to this.
+ cx.validate_operand(&ot).is_ok()
+}
+
+/// Implements the 'lax' (default) version of the `might_permit_raw_init` checks; see that function for
+/// details.
+fn might_permit_raw_init_lax<'tcx>(
+ this: TyAndLayout<'tcx>,
+ cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+ init_kind: InitKind,
+) -> bool {
+ let scalar_allows_raw_init = move |s: Scalar| -> bool {
+ match init_kind {
+ InitKind::Zero => {
+ // The range must contain 0.
+ s.valid_range(cx).contains(0)
+ }
+ InitKind::UninitMitigated0x01Fill => {
+ // The range must include an 0x01-filled buffer.
+ let mut val: u128 = 0x01;
+ for _ in 1..s.size(cx).bytes() {
+ // For sizes >1, repeat the 0x01.
+ val = (val << 8) | 0x01;
+ }
+ s.valid_range(cx).contains(val)
+ }
+ }
+ };
+
+ // Check the ABI.
+ let valid = match this.abi {
+ Abi::Uninhabited => false, // definitely UB
+ Abi::Scalar(s) => scalar_allows_raw_init(s),
+ Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2),
+ Abi::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s),
+ Abi::Aggregate { .. } => true, // Fields are checked below.
+ };
+ if !valid {
+ // This is definitely not okay.
+ return false;
+ }
+
+ // Special magic check for references and boxes (i.e., special pointer types).
+ if let Some(pointee) = this.ty.builtin_deref(false) {
+ let pointee = cx.layout_of(pointee.ty).expect("need to be able to compute layouts");
+ // We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied.
+ if pointee.align.abi.bytes() > 1 {
+ // 0x01-filling is not aligned.
+ return false;
+ }
+ if pointee.size.bytes() > 0 {
+ // A 'fake' integer pointer is not sufficiently dereferenceable.
+ return false;
+ }
+ }
+
+ // If we have not found an error yet, we need to recursively descend into fields.
+ match &this.fields {
+ FieldsShape::Primitive | FieldsShape::Union { .. } => {}
+ FieldsShape::Array { .. } => {
+ // Arrays never have scalar layout in LLVM, so if the array is not actually
+ // accessed, there is no LLVM UB -- therefore we can skip this.
+ }
+ FieldsShape::Arbitrary { offsets, .. } => {
+ for idx in 0..offsets.len() {
+ if !might_permit_raw_init_lax(this.field(cx, idx), cx, init_kind) {
+ // We found a field that is unhappy with this kind of initialization.
+ return false;
+ }
+ }
+ }
+ }
+
+ match &this.variants {
+ Variants::Single { .. } => {
+ // All fields of this single variant have already been checked above, there is nothing
+ // else to do.
+ }
+ Variants::Multiple { .. } => {
+ // We cannot tell LLVM anything about the details of this multi-variant layout, so
+ // invalid values "hidden" inside the variant cannot cause LLVM trouble.
+ }
+ }
+
+ true
+}
diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs
index a1876bed8..7a05cfd23 100644
--- a/compiler/rustc_const_eval/src/util/mod.rs
+++ b/compiler/rustc_const_eval/src/util/mod.rs
@@ -3,8 +3,10 @@ mod alignment;
mod call_kind;
pub mod collect_writes;
mod find_self_call;
+mod might_permit_raw_init;
pub use self::aggregate::expand_aggregate;
pub use self::alignment::is_disaligned;
pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
pub use self::find_self_call::find_self_call;
+pub use self::might_permit_raw_init::might_permit_raw_init;
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 2d8658db5..9daa21ef6 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
arrayvec = { version = "0.7", default-features = false }
diff --git a/compiler/rustc_data_structures/src/flock/linux.rs b/compiler/rustc_data_structures/src/flock/linux.rs
index bb3ecfbc3..9ed26e490 100644
--- a/compiler/rustc_data_structures/src/flock/linux.rs
+++ b/compiler/rustc_data_structures/src/flock/linux.rs
@@ -14,12 +14,7 @@ pub struct Lock {
impl Lock {
pub fn new(p: &Path, wait: bool, create: bool, exclusive: bool) -> io::Result<Lock> {
- let file = OpenOptions::new()
- .read(true)
- .write(true)
- .create(create)
- .mode(libc::S_IRWXU as u32)
- .open(p)?;
+ let file = OpenOptions::new().read(true).write(true).create(create).mode(0o600).open(p)?;
let mut operation = if exclusive { libc::LOCK_EX } else { libc::LOCK_SH };
if !wait {
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 3d91bcade..e8efbd09a 100644
--- a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
@@ -29,8 +29,8 @@ impl<N: Idx + Ord> VecGraph<N> {
// Store the *target* of each edge into `edge_targets`.
let edge_targets: Vec<N> = edge_pairs.iter().map(|&(_, target)| target).collect();
- // Create the *edge starts* array. We are iterating over over
- // the (sorted) edge pairs. We maintain the invariant that the
+ // Create the *edge starts* array. We are iterating over the
+ // (sorted) edge pairs. We maintain the invariant that the
// length of the `node_starts` array is enough to store the
// current source node -- so when we see that the source node
// for an edge is greater than the current length, we grow the
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 56f7823ef..3a2000233 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -13,7 +13,6 @@
#![feature(cell_leak)]
#![feature(control_flow_enum)]
#![feature(extend_one)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(hash_raw_entry)]
#![feature(hasher_prefixfree_extras)]
#![feature(maybe_uninit_uninit_array)]
@@ -23,6 +22,7 @@
#![feature(new_uninit)]
#![feature(once_cell)]
#![feature(rustc_attrs)]
+#![feature(negative_impls)]
#![feature(test)]
#![feature(thread_id_value)]
#![feature(vec_into_raw_parts)]
@@ -87,6 +87,7 @@ pub mod steal;
pub mod tagged_ptr;
pub mod temp_dir;
pub mod unhash;
+pub mod unord;
pub use ena::undo_log;
pub use ena::unify;
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index e351b650a..10e673cd9 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -95,6 +95,10 @@ pub trait ForestObligation: Clone + Debug {
pub trait ObligationProcessor {
type Obligation: ForestObligation;
type Error: Debug;
+ type OUT: OutcomeTrait<
+ Obligation = Self::Obligation,
+ Error = Error<Self::Obligation, Self::Error>,
+ >;
fn needs_process_obligation(&self, obligation: &Self::Obligation) -> bool;
@@ -111,7 +115,11 @@ pub trait ObligationProcessor {
/// In other words, if we had O1 which required O2 which required
/// O3 which required O1, we would give an iterator yielding O1,
/// O2, O3 (O1 is not yielded twice).
- fn process_backedge<'c, I>(&mut self, cycle: I, _marker: PhantomData<&'c Self::Obligation>)
+ fn process_backedge<'c, I>(
+ &mut self,
+ cycle: I,
+ _marker: PhantomData<&'c Self::Obligation>,
+ ) -> Result<(), Self::Error>
where
I: Clone + Iterator<Item = &'c Self::Obligation>;
}
@@ -402,12 +410,11 @@ impl<O: ForestObligation> ObligationForest<O> {
/// Performs a fixpoint computation over the obligation list.
#[inline(never)]
- pub fn process_obligations<P, OUT>(&mut self, processor: &mut P) -> OUT
+ pub fn process_obligations<P>(&mut self, processor: &mut P) -> P::OUT
where
P: ObligationProcessor<Obligation = O>,
- OUT: OutcomeTrait<Obligation = O, Error = Error<O, P::Error>>,
{
- let mut outcome = OUT::new();
+ let mut outcome = P::OUT::new();
// Fixpoint computation: we repeat until the inner loop stalls.
loop {
@@ -473,7 +480,7 @@ impl<O: ForestObligation> ObligationForest<O> {
}
self.mark_successes();
- self.process_cycles(processor);
+ self.process_cycles(processor, &mut outcome);
self.compress(|obl| outcome.record_completed(obl));
}
@@ -558,7 +565,7 @@ impl<O: ForestObligation> ObligationForest<O> {
/// Report cycles between all `Success` nodes, and convert all `Success`
/// nodes to `Done`. This must be called after `mark_successes`.
- fn process_cycles<P>(&mut self, processor: &mut P)
+ fn process_cycles<P>(&mut self, processor: &mut P, outcome: &mut P::OUT)
where
P: ObligationProcessor<Obligation = O>,
{
@@ -568,7 +575,7 @@ impl<O: ForestObligation> ObligationForest<O> {
// to handle the no-op cases immediately to avoid the cost of the
// function call.
if node.state.get() == NodeState::Success {
- self.find_cycles_from_node(&mut stack, processor, index);
+ self.find_cycles_from_node(&mut stack, processor, index, outcome);
}
}
@@ -576,8 +583,13 @@ impl<O: ForestObligation> ObligationForest<O> {
self.reused_node_vec = stack;
}
- fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, index: usize)
- where
+ fn find_cycles_from_node<P>(
+ &self,
+ stack: &mut Vec<usize>,
+ processor: &mut P,
+ index: usize,
+ outcome: &mut P::OUT,
+ ) where
P: ObligationProcessor<Obligation = O>,
{
let node = &self.nodes[index];
@@ -586,17 +598,20 @@ impl<O: ForestObligation> ObligationForest<O> {
None => {
stack.push(index);
for &dep_index in node.dependents.iter() {
- self.find_cycles_from_node(stack, processor, dep_index);
+ self.find_cycles_from_node(stack, processor, dep_index, outcome);
}
stack.pop();
node.state.set(NodeState::Done);
}
Some(rpos) => {
// Cycle detected.
- processor.process_backedge(
+ let result = processor.process_backedge(
stack[rpos..].iter().map(|&i| &self.nodes[i].obligation),
PhantomData,
);
+ if let Err(err) = result {
+ outcome.record_error(Error { error: err, backtrace: self.error_at(index) });
+ }
}
}
}
diff --git a/compiler/rustc_data_structures/src/obligation_forest/tests.rs b/compiler/rustc_data_structures/src/obligation_forest/tests.rs
index e2991aae1..bc252f772 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/tests.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/tests.rs
@@ -64,6 +64,7 @@ where
{
type Obligation = O;
type Error = E;
+ type OUT = TestOutcome<O, E>;
fn needs_process_obligation(&self, _obligation: &Self::Obligation) -> bool {
true
@@ -76,10 +77,15 @@ where
(self.process_obligation)(obligation)
}
- fn process_backedge<'c, I>(&mut self, _cycle: I, _marker: PhantomData<&'c Self::Obligation>)
+ fn process_backedge<'c, I>(
+ &mut self,
+ _cycle: I,
+ _marker: PhantomData<&'c Self::Obligation>,
+ ) -> Result<(), Self::Error>
where
I: Clone + Iterator<Item = &'c Self::Obligation>,
{
+ Ok(())
}
}
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index d8b26f984..ba1960805 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -158,30 +158,21 @@ pub struct SelfProfilerRef {
// actually enabled.
event_filter_mask: EventFilter,
- // Print verbose generic activities to stdout
+ // Print verbose generic activities to stderr?
print_verbose_generic_activities: bool,
-
- // Print extra verbose generic activities to stdout
- print_extra_verbose_generic_activities: bool,
}
impl SelfProfilerRef {
pub fn new(
profiler: Option<Arc<SelfProfiler>>,
print_verbose_generic_activities: bool,
- print_extra_verbose_generic_activities: bool,
) -> SelfProfilerRef {
// If there is no SelfProfiler then the filter mask is set to NONE,
// ensuring that nothing ever tries to actually access it.
let event_filter_mask =
profiler.as_ref().map_or(EventFilter::empty(), |p| p.event_filter_mask);
- SelfProfilerRef {
- profiler,
- event_filter_mask,
- print_verbose_generic_activities,
- print_extra_verbose_generic_activities,
- }
+ SelfProfilerRef { profiler, event_filter_mask, print_verbose_generic_activities }
}
/// This shim makes sure that calls only get executed if the filter mask
@@ -214,7 +205,7 @@ impl SelfProfilerRef {
/// Start profiling a verbose generic activity. Profiling continues until the
/// VerboseTimingGuard returned from this call is dropped. In addition to recording
/// a measureme event, "verbose" generic activities also print a timing entry to
- /// stdout if the compiler is invoked with -Ztime or -Ztime-passes.
+ /// stderr if the compiler is invoked with -Ztime-passes.
pub fn verbose_generic_activity<'a>(
&'a self,
event_label: &'static str,
@@ -225,11 +216,8 @@ impl SelfProfilerRef {
VerboseTimingGuard::start(message, self.generic_activity(event_label))
}
- /// Start profiling an extra verbose generic activity. Profiling continues until the
- /// VerboseTimingGuard returned from this call is dropped. In addition to recording
- /// a measureme event, "extra verbose" generic activities also print a timing entry to
- /// stdout if the compiler is invoked with -Ztime-passes.
- pub fn extra_verbose_generic_activity<'a, A>(
+ /// Like `verbose_generic_activity`, but with an extra arg.
+ pub fn verbose_generic_activity_with_arg<'a, A>(
&'a self,
event_label: &'static str,
event_arg: A,
@@ -237,7 +225,7 @@ impl SelfProfilerRef {
where
A: Borrow<str> + Into<String>,
{
- let message = if self.print_extra_verbose_generic_activities {
+ let message = if self.print_verbose_generic_activities {
Some(format!("{}({})", event_label, event_arg.borrow()))
} else {
None
@@ -745,27 +733,9 @@ impl Drop for VerboseTimingGuard<'_> {
if let Some((start_time, start_rss, ref message)) = self.start_and_message {
let end_rss = get_resident_set_size();
let dur = start_time.elapsed();
-
- if should_print_passes(dur, start_rss, end_rss) {
- print_time_passes_entry(&message, dur, start_rss, end_rss);
- }
- }
- }
-}
-
-fn should_print_passes(dur: Duration, start_rss: Option<usize>, end_rss: Option<usize>) -> bool {
- if dur.as_millis() > 5 {
- return true;
- }
-
- if let (Some(start_rss), Some(end_rss)) = (start_rss, end_rss) {
- let change_rss = end_rss.abs_diff(start_rss);
- if change_rss > 0 {
- return true;
+ print_time_passes_entry(&message, dur, start_rss, end_rss);
}
}
-
- false
}
pub fn print_time_passes_entry(
@@ -774,6 +744,26 @@ pub fn print_time_passes_entry(
start_rss: Option<usize>,
end_rss: Option<usize>,
) {
+ // Print the pass if its duration is greater than 5 ms, or it changed the
+ // measured RSS.
+ let is_notable = || {
+ if dur.as_millis() > 5 {
+ return true;
+ }
+
+ if let (Some(start_rss), Some(end_rss)) = (start_rss, end_rss) {
+ let change_rss = end_rss.abs_diff(start_rss);
+ if change_rss > 0 {
+ return true;
+ }
+ }
+
+ false
+ };
+ if !is_notable() {
+ return;
+ }
+
let rss_to_mb = |rss| (rss as f64 / 1_000_000.0).round() as usize;
let rss_change_to_mb = |rss| (rss as f64 / 1_000_000.0).round() as i128;
diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs
index 937cb6715..fe257e102 100644
--- a/compiler/rustc_data_structures/src/sorted_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map.rs
@@ -96,6 +96,23 @@ impl<K: Ord, V> SortedMap<K, V> {
}
}
+ /// Gets a mutable reference to the value in the entry, or insert a new one.
+ #[inline]
+ pub fn get_mut_or_insert_default(&mut self, key: K) -> &mut V
+ where
+ K: Eq,
+ V: Default,
+ {
+ let index = match self.lookup_index_for(&key) {
+ Ok(index) => index,
+ Err(index) => {
+ self.data.insert(index, (key, V::default()));
+ index
+ }
+ };
+ unsafe { &mut self.data.get_unchecked_mut(index).1 }
+ }
+
#[inline]
pub fn clear(&mut self) {
self.data.clear();
diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs
index 4fda3adb7..406f0270d 100644
--- a/compiler/rustc_data_structures/src/sso/set.rs
+++ b/compiler/rustc_data_structures/src/sso/set.rs
@@ -27,7 +27,7 @@ pub struct SsoHashSet<T> {
map: SsoHashMap<T, ()>,
}
-/// Adapter function used ot return
+/// Adapter function used to return
/// result if SsoHashMap functions into
/// result SsoHashSet should return.
#[inline(always)]
diff --git a/compiler/rustc_data_structures/src/transitive_relation.rs b/compiler/rustc_data_structures/src/transitive_relation.rs
index f016c391f..cf6162038 100644
--- a/compiler/rustc_data_structures/src/transitive_relation.rs
+++ b/compiler/rustc_data_structures/src/transitive_relation.rs
@@ -1,5 +1,5 @@
use crate::frozen::Frozen;
-use crate::fx::FxIndexSet;
+use crate::fx::{FxHashSet, FxIndexSet};
use rustc_index::bit_set::BitMatrix;
use std::fmt::Debug;
use std::hash::Hash;
@@ -16,7 +16,7 @@ pub struct TransitiveRelationBuilder<T> {
// List of base edges in the graph. Require to compute transitive
// closure.
- edges: Vec<Edge>,
+ edges: FxHashSet<Edge>,
}
#[derive(Debug)]
@@ -52,10 +52,10 @@ impl<T: Eq + Hash> Default for TransitiveRelationBuilder<T> {
}
}
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug, Hash)]
struct Index(usize);
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
struct Edge {
source: Index,
target: Index,
@@ -99,9 +99,7 @@ impl<T: Eq + Hash + Copy> TransitiveRelationBuilder<T> {
let a = self.add_index(a);
let b = self.add_index(b);
let edge = Edge { source: a, target: b };
- if !self.edges.contains(&edge) {
- self.edges.push(edge);
- }
+ self.edges.insert(edge);
}
/// Compute the transitive closure derived from the edges, and converted to
diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs
new file mode 100644
index 000000000..c015f1232
--- /dev/null
+++ b/compiler/rustc_data_structures/src/unord.rs
@@ -0,0 +1,382 @@
+//! This module contains collection types that don't expose their internal
+//! ordering. This is a useful property for deterministic computations, such
+//! as required by the query system.
+
+use rustc_hash::{FxHashMap, FxHashSet};
+use smallvec::SmallVec;
+use std::{
+ borrow::Borrow,
+ hash::Hash,
+ iter::{Product, Sum},
+};
+
+use crate::{
+ fingerprint::Fingerprint,
+ stable_hasher::{HashStable, StableHasher, ToStableHashKey},
+};
+
+/// `UnordItems` is the order-less version of `Iterator`. It only contains methods
+/// that don't (easily) expose an ordering of the underlying items.
+///
+/// Most methods take an `Fn` where the `Iterator`-version takes an `FnMut`. This
+/// is to reduce the risk of accidentally leaking the internal order via the closure
+/// environment. Otherwise one could easily do something like
+///
+/// ```rust,ignore (pseudo code)
+/// let mut ordered = vec![];
+/// unordered_items.all(|x| ordered.push(x));
+/// ```
+///
+/// It's still possible to do the same thing with an `Fn` by using interior mutability,
+/// but the chance of doing it accidentally is reduced.
+pub struct UnordItems<T, I: Iterator<Item = T>>(I);
+
+impl<T, I: Iterator<Item = T>> UnordItems<T, I> {
+ #[inline]
+ pub fn map<U, F: Fn(T) -> U>(self, f: F) -> UnordItems<U, impl Iterator<Item = U>> {
+ UnordItems(self.0.map(f))
+ }
+
+ #[inline]
+ pub fn all<U, F: Fn(T) -> bool>(mut self, f: F) -> bool {
+ self.0.all(f)
+ }
+
+ #[inline]
+ pub fn any<U, F: Fn(T) -> bool>(mut self, f: F) -> bool {
+ self.0.any(f)
+ }
+
+ #[inline]
+ pub fn filter<U, F: Fn(&T) -> bool>(self, f: F) -> UnordItems<T, impl Iterator<Item = T>> {
+ UnordItems(self.0.filter(f))
+ }
+
+ #[inline]
+ pub fn filter_map<U, F: Fn(T) -> Option<U>>(
+ self,
+ f: F,
+ ) -> UnordItems<U, impl Iterator<Item = U>> {
+ UnordItems(self.0.filter_map(f))
+ }
+
+ #[inline]
+ pub fn max(self) -> Option<T>
+ where
+ T: Ord,
+ {
+ self.0.max()
+ }
+
+ #[inline]
+ pub fn min(self) -> Option<T>
+ where
+ T: Ord,
+ {
+ self.0.min()
+ }
+
+ #[inline]
+ pub fn sum<S>(self) -> S
+ where
+ S: Sum<T>,
+ {
+ self.0.sum()
+ }
+
+ #[inline]
+ pub fn product<S>(self) -> S
+ where
+ S: Product<T>,
+ {
+ self.0.product()
+ }
+
+ #[inline]
+ pub fn count(self) -> usize {
+ self.0.count()
+ }
+}
+
+impl<'a, T: Clone + 'a, I: Iterator<Item = &'a T>> UnordItems<&'a T, I> {
+ #[inline]
+ pub fn cloned(self) -> UnordItems<T, impl Iterator<Item = T>> {
+ UnordItems(self.0.cloned())
+ }
+}
+
+impl<'a, T: Copy + 'a, I: Iterator<Item = &'a T>> UnordItems<&'a T, I> {
+ #[inline]
+ pub fn copied(self) -> UnordItems<T, impl Iterator<Item = T>> {
+ UnordItems(self.0.copied())
+ }
+}
+
+impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> {
+ pub fn into_sorted<HCX>(self, hcx: &HCX) -> Vec<T>
+ where
+ T: ToStableHashKey<HCX>,
+ {
+ let mut items: Vec<T> = self.0.collect();
+ items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx));
+ items
+ }
+
+ pub fn into_sorted_small_vec<HCX, const LEN: usize>(self, hcx: &HCX) -> SmallVec<[T; LEN]>
+ where
+ T: ToStableHashKey<HCX>,
+ {
+ let mut items: SmallVec<[T; LEN]> = self.0.collect();
+ items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx));
+ items
+ }
+}
+
+/// This is a set collection type that tries very hard to not expose
+/// any internal iteration. This is a useful property when trying to
+/// uphold the determinism invariants imposed by the query system.
+///
+/// This collection type is a good choice for set-like collections the
+/// keys of which don't have a semantic ordering.
+///
+/// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533)
+/// for more information.
+#[derive(Debug, Eq, PartialEq, Clone, Encodable, Decodable)]
+pub struct UnordSet<V: Eq + Hash> {
+ inner: FxHashSet<V>,
+}
+
+impl<V: Eq + Hash> Default for UnordSet<V> {
+ fn default() -> Self {
+ Self { inner: FxHashSet::default() }
+ }
+}
+
+impl<V: Eq + Hash> UnordSet<V> {
+ #[inline]
+ pub fn new() -> Self {
+ Self { inner: Default::default() }
+ }
+
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.inner.len()
+ }
+
+ #[inline]
+ pub fn insert(&mut self, v: V) -> bool {
+ self.inner.insert(v)
+ }
+
+ #[inline]
+ pub fn contains<Q: ?Sized>(&self, v: &Q) -> bool
+ where
+ V: Borrow<Q>,
+ Q: Hash + Eq,
+ {
+ self.inner.contains(v)
+ }
+
+ #[inline]
+ pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator<Item = &'a V>> {
+ UnordItems(self.inner.iter())
+ }
+
+ #[inline]
+ pub fn into_items(self) -> UnordItems<V, impl Iterator<Item = V>> {
+ UnordItems(self.inner.into_iter())
+ }
+
+ // We can safely extend this UnordSet from a set of unordered values because that
+ // won't expose the internal ordering anywhere.
+ #[inline]
+ pub fn extend<I: Iterator<Item = V>>(&mut self, items: UnordItems<V, I>) {
+ self.inner.extend(items.0)
+ }
+}
+
+impl<V: Hash + Eq> Extend<V> for UnordSet<V> {
+ fn extend<T: IntoIterator<Item = V>>(&mut self, iter: T) {
+ self.inner.extend(iter)
+ }
+}
+
+impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordSet<V> {
+ #[inline]
+ fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
+ hash_iter_order_independent(self.inner.iter(), hcx, hasher);
+ }
+}
+
+/// This is a map collection type that tries very hard to not expose
+/// any internal iteration. This is a useful property when trying to
+/// uphold the determinism invariants imposed by the query system.
+///
+/// This collection type is a good choice for map-like collections the
+/// keys of which don't have a semantic ordering.
+///
+/// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533)
+/// for more information.
+#[derive(Debug, Eq, PartialEq, Clone, Encodable, Decodable)]
+pub struct UnordMap<K: Eq + Hash, V> {
+ inner: FxHashMap<K, V>,
+}
+
+impl<K: Eq + Hash, V> Default for UnordMap<K, V> {
+ fn default() -> Self {
+ Self { inner: FxHashMap::default() }
+ }
+}
+
+impl<K: Hash + Eq, V> Extend<(K, V)> for UnordMap<K, V> {
+ fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
+ self.inner.extend(iter)
+ }
+}
+
+impl<K: Eq + Hash, V> UnordMap<K, V> {
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.inner.len()
+ }
+
+ #[inline]
+ pub fn insert(&mut self, k: K, v: V) -> Option<V> {
+ self.inner.insert(k, v)
+ }
+
+ #[inline]
+ pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
+ where
+ K: Borrow<Q>,
+ Q: Hash + Eq,
+ {
+ self.inner.contains_key(k)
+ }
+
+ #[inline]
+ pub fn items<'a>(&'a self) -> UnordItems<(&'a K, &'a V), impl Iterator<Item = (&'a K, &'a V)>> {
+ UnordItems(self.inner.iter())
+ }
+
+ #[inline]
+ pub fn into_items(self) -> UnordItems<(K, V), impl Iterator<Item = (K, V)>> {
+ UnordItems(self.inner.into_iter())
+ }
+
+ // We can safely extend this UnordMap from a set of unordered values because that
+ // won't expose the internal ordering anywhere.
+ #[inline]
+ pub fn extend<I: Iterator<Item = (K, V)>>(&mut self, items: UnordItems<(K, V), I>) {
+ self.inner.extend(items.0)
+ }
+}
+
+impl<HCX, K: Hash + Eq + HashStable<HCX>, V: HashStable<HCX>> HashStable<HCX> for UnordMap<K, V> {
+ #[inline]
+ fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
+ hash_iter_order_independent(self.inner.iter(), hcx, hasher);
+ }
+}
+
+/// This is a collection type that tries very hard to not expose
+/// any internal iteration. This is a useful property when trying to
+/// uphold the determinism invariants imposed by the query system.
+///
+/// This collection type is a good choice for collections the
+/// keys of which don't have a semantic ordering and don't implement
+/// `Hash` or `Eq`.
+///
+/// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533)
+/// for more information.
+#[derive(Default, Debug, Eq, PartialEq, Clone, Encodable, Decodable)]
+pub struct UnordBag<V> {
+ inner: Vec<V>,
+}
+
+impl<V> UnordBag<V> {
+ #[inline]
+ pub fn new() -> Self {
+ Self { inner: Default::default() }
+ }
+
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.inner.len()
+ }
+
+ #[inline]
+ pub fn push(&mut self, v: V) {
+ self.inner.push(v);
+ }
+
+ #[inline]
+ pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator<Item = &'a V>> {
+ UnordItems(self.inner.iter())
+ }
+
+ #[inline]
+ pub fn into_items(self) -> UnordItems<V, impl Iterator<Item = V>> {
+ UnordItems(self.inner.into_iter())
+ }
+
+ // We can safely extend this UnordSet from a set of unordered values because that
+ // won't expose the internal ordering anywhere.
+ #[inline]
+ pub fn extend<I: Iterator<Item = V>>(&mut self, items: UnordItems<V, I>) {
+ self.inner.extend(items.0)
+ }
+}
+
+impl<T> Extend<T> for UnordBag<T> {
+ fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+ self.inner.extend(iter)
+ }
+}
+
+impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordBag<V> {
+ #[inline]
+ fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
+ hash_iter_order_independent(self.inner.iter(), hcx, hasher);
+ }
+}
+
+fn hash_iter_order_independent<
+ HCX,
+ T: HashStable<HCX>,
+ I: Iterator<Item = T> + ExactSizeIterator,
+>(
+ mut it: I,
+ hcx: &mut HCX,
+ hasher: &mut StableHasher,
+) {
+ let len = it.len();
+ len.hash_stable(hcx, hasher);
+
+ match len {
+ 0 => {
+ // We're done
+ }
+ 1 => {
+ // No need to instantiate a hasher
+ it.next().unwrap().hash_stable(hcx, hasher);
+ }
+ _ => {
+ let mut accumulator = Fingerprint::ZERO;
+ for item in it {
+ let mut item_hasher = StableHasher::new();
+ item.hash_stable(hcx, &mut item_hasher);
+ let item_fingerprint: Fingerprint = item_hasher.finish();
+ accumulator = accumulator.combine_commutative(item_fingerprint);
+ }
+ accumulator.hash_stable(hcx, hasher);
+ }
+ }
+}
+
+// Do not implement IntoIterator for the collections in this module.
+// They only exist to hide iteration order in the first place.
+impl<T> !IntoIterator for UnordBag<T> {}
+impl<V> !IntoIterator for UnordSet<V> {}
+impl<K, V> !IntoIterator for UnordMap<K, V> {}
+impl<T, I> !IntoIterator for UnordItems<T, I> {}
diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml
index d1d02ed73..59e937777 100644
--- a/compiler/rustc_driver/Cargo.toml
+++ b/compiler/rustc_driver/Cargo.toml
@@ -30,7 +30,7 @@ rustc_error_codes = { path = "../rustc_error_codes" }
rustc_interface = { path = "../rustc_interface" }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
-rustc_typeck = { path = "../rustc_typeck" }
+rustc_hir_analysis = { path = "../rustc_hir_analysis" }
[target.'cfg(unix)'.dependencies]
libc = "0.2"
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 8fb950819..cfa734c7d 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -5,7 +5,6 @@
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(once_cell)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
@@ -36,7 +35,7 @@ use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, Tr
use rustc_session::cstore::MetadataLoader;
use rustc_session::getopts;
use rustc_session::lint::{Lint, LintId};
-use rustc_session::{config, DiagnosticOutput, Session};
+use rustc_session::{config, Session};
use rustc_session::{early_error, early_error_no_abort, early_warn};
use rustc_span::source_map::{FileLoader, FileName};
use rustc_span::symbol::sym;
@@ -128,10 +127,13 @@ pub struct TimePassesCallbacks {
}
impl Callbacks for TimePassesCallbacks {
+ // JUSTIFICATION: the session doesn't exist at this point.
+ #[allow(rustc::bad_opt_access)]
fn config(&mut self, config: &mut interface::Config) {
- // If a --prints=... option has been given, we don't print the "total"
- // time because it will mess up the --prints output. See #64339.
- self.time_passes = config.opts.prints.is_empty() && config.opts.time_passes();
+ // If a --print=... option has been given, we don't print the "total"
+ // time because it will mess up the --print output. See #64339.
+ //
+ self.time_passes = config.opts.prints.is_empty() && config.opts.unstable_opts.time_passes;
config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath;
}
}
@@ -145,19 +147,21 @@ pub struct RunCompiler<'a, 'b> {
at_args: &'a [String],
callbacks: &'b mut (dyn Callbacks + Send),
file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
- emitter: Option<Box<dyn Write + Send>>,
make_codegen_backend:
Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
}
impl<'a, 'b> RunCompiler<'a, 'b> {
pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self {
- Self { at_args, callbacks, file_loader: None, emitter: None, make_codegen_backend: None }
+ Self { at_args, callbacks, file_loader: None, make_codegen_backend: None }
}
/// Set a custom codegen backend.
///
- /// Used by cg_clif.
+ /// Has no uses within this repository, but is used by bjorn3 for "the
+ /// hotswapping branch of cg_clif" for "setting the codegen backend from a
+ /// custom driver where the custom codegen backend has arbitrary data."
+ /// (See #102759.)
pub fn set_make_codegen_backend(
&mut self,
make_codegen_backend: Option<
@@ -168,17 +172,11 @@ impl<'a, 'b> RunCompiler<'a, 'b> {
self
}
- /// Emit diagnostics to the specified location.
- ///
- /// Used by RLS.
- pub fn set_emitter(&mut self, emitter: Option<Box<dyn Write + Send>>) -> &mut Self {
- self.emitter = emitter;
- self
- }
-
/// Load files from sources other than the file system.
///
- /// Used by RLS.
+ /// Has no uses within this repository, but may be used in the future by
+ /// bjorn3 for "hooking rust-analyzer's VFS into rustc at some point for
+ /// running rustc without having to save". (See #102759.)
pub fn set_file_loader(
&mut self,
file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
@@ -189,27 +187,20 @@ impl<'a, 'b> RunCompiler<'a, 'b> {
/// Parse args and run the compiler.
pub fn run(self) -> interface::Result<()> {
- run_compiler(
- self.at_args,
- self.callbacks,
- self.file_loader,
- self.emitter,
- self.make_codegen_backend,
- )
+ run_compiler(self.at_args, self.callbacks, self.file_loader, self.make_codegen_backend)
}
}
+
fn run_compiler(
at_args: &[String],
callbacks: &mut (dyn Callbacks + Send),
file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
- emitter: Option<Box<dyn Write + Send>>,
make_codegen_backend: Option<
Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
>,
) -> interface::Result<()> {
let args = args::arg_expand_all(at_args);
- let diagnostic_output = emitter.map_or(DiagnosticOutput::Default, DiagnosticOutput::Raw);
let Some(matches) = handle_options(&args) else { return Ok(()) };
let sopts = config::build_session_options(&matches);
@@ -231,7 +222,6 @@ fn run_compiler(
output_file: ofile,
output_dir: odir,
file_loader,
- diagnostic_output,
lint_caps: Default::default(),
parse_sess_created: None,
register_lints: None,
@@ -437,18 +427,6 @@ fn run_compiler(
})
}
-#[cfg(unix)]
-pub fn set_sigpipe_handler() {
- unsafe {
- // Set the SIGPIPE signal handler, so that an EPIPE
- // will cause rustc to terminate, as expected.
- assert_ne!(libc::signal(libc::SIGPIPE, libc::SIG_DFL), libc::SIG_ERR);
- }
-}
-
-#[cfg(windows)]
-pub fn set_sigpipe_handler() {}
-
// Extract output directory and file from matches.
fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) {
let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
@@ -742,6 +720,11 @@ fn print_crate_info(
println!("{}", cfg);
}
}
+ CallingConventions => {
+ let mut calling_conventions = rustc_target::spec::abi::all_names();
+ calling_conventions.sort_unstable();
+ println!("{}", calling_conventions.join("\n"));
+ }
RelocationModels
| CodeModels
| TlsModels
diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs
index 2874fa0ca..f9b1316d2 100644
--- a/compiler/rustc_driver/src/pretty.rs
+++ b/compiler/rustc_driver/src/pretty.rs
@@ -329,7 +329,7 @@ impl<'tcx> pprust_hir::PpAnn for TypedAnnotation<'tcx> {
let typeck_results = self.maybe_typeck_results.get().or_else(|| {
self.tcx
.hir()
- .maybe_body_owned_by(expr.hir_id.owner)
+ .maybe_body_owned_by(expr.hir_id.owner.def_id)
.map(|body_id| self.tcx.typeck_body(body_id))
});
@@ -502,7 +502,7 @@ fn print_with_analysis(
ThirTree => {
let mut out = String::new();
- abort_on_err(rustc_typeck::check_crate(tcx), tcx.sess);
+ 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!(
diff --git a/compiler/rustc_driver/src/session_diagnostics.rs b/compiler/rustc_driver/src/session_diagnostics.rs
index e9696792d..c1bc10891 100644
--- a/compiler/rustc_driver/src/session_diagnostics.rs
+++ b/compiler/rustc_driver/src/session_diagnostics.rs
@@ -1,39 +1,39 @@
-use rustc_macros::SessionDiagnostic;
+use rustc_macros::Diagnostic;
-#[derive(SessionDiagnostic)]
-#[diag(driver::rlink_unable_to_read)]
+#[derive(Diagnostic)]
+#[diag(driver_rlink_unable_to_read)]
pub(crate) struct RlinkUnableToRead {
pub err: std::io::Error,
}
-#[derive(SessionDiagnostic)]
-#[diag(driver::rlink_wrong_file_type)]
+#[derive(Diagnostic)]
+#[diag(driver_rlink_wrong_file_type)]
pub(crate) struct RLinkWrongFileType;
-#[derive(SessionDiagnostic)]
-#[diag(driver::rlink_empty_version_number)]
+#[derive(Diagnostic)]
+#[diag(driver_rlink_empty_version_number)]
pub(crate) struct RLinkEmptyVersionNumber;
-#[derive(SessionDiagnostic)]
-#[diag(driver::rlink_encoding_version_mismatch)]
+#[derive(Diagnostic)]
+#[diag(driver_rlink_encoding_version_mismatch)]
pub(crate) struct RLinkEncodingVersionMismatch {
pub version_array: String,
pub rlink_version: u32,
}
-#[derive(SessionDiagnostic)]
-#[diag(driver::rlink_rustc_version_mismatch)]
+#[derive(Diagnostic)]
+#[diag(driver_rlink_rustc_version_mismatch)]
pub(crate) struct RLinkRustcVersionMismatch<'a> {
pub rustc_version: String,
pub current_version: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(driver::rlink_no_a_file)]
+#[derive(Diagnostic)]
+#[diag(driver_rlink_no_a_file)]
pub(crate) struct RlinkNotAFile;
-#[derive(SessionDiagnostic)]
-#[diag(driver::unpretty_dump_fail)]
+#[derive(Diagnostic)]
+#[diag(driver_unpretty_dump_fail)]
pub(crate) struct UnprettyDumpFail {
pub path: String,
pub err: String,
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 854625579..1e86d1596 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -159,6 +159,7 @@ E0307: include_str!("./error_codes/E0307.md"),
E0308: include_str!("./error_codes/E0308.md"),
E0309: include_str!("./error_codes/E0309.md"),
E0310: include_str!("./error_codes/E0310.md"),
+E0311: include_str!("./error_codes/E0311.md"),
E0312: include_str!("./error_codes/E0312.md"),
E0316: include_str!("./error_codes/E0316.md"),
E0317: include_str!("./error_codes/E0317.md"),
@@ -568,7 +569,6 @@ E0790: include_str!("./error_codes/E0790.md"),
// E0300, // unexpanded macro
// E0304, // expected signed integer constant
// E0305, // expected constant
- E0311, // thing may not live long enough
E0313, // lifetime of borrowed pointer outlives lifetime of captured
// variable
// E0314, // closure outlives stack frame
diff --git a/compiler/rustc_error_codes/src/error_codes/E0045.md b/compiler/rustc_error_codes/src/error_codes/E0045.md
index 143c693bf..1cb214531 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0045.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0045.md
@@ -3,9 +3,7 @@ Variadic parameters have been used on a non-C ABI function.
Erroneous code example:
```compile_fail,E0045
-#![feature(unboxed_closures)]
-
-extern "rust-call" {
+extern "Rust" {
fn foo(x: u8, ...); // error!
}
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0092.md b/compiler/rustc_error_codes/src/error_codes/E0092.md
index 496174b28..5cbe2a188 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0092.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0092.md
@@ -19,6 +19,6 @@ functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in
#![feature(intrinsics)]
extern "rust-intrinsic" {
- fn atomic_fence(); // ok!
+ fn atomic_fence_seqcst(); // ok!
}
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0094.md b/compiler/rustc_error_codes/src/error_codes/E0094.md
index ec86ec44e..cc546bdbb 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0094.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0094.md
@@ -6,6 +6,7 @@ Erroneous code example:
#![feature(intrinsics)]
extern "rust-intrinsic" {
+ #[rustc_safe_intrinsic]
fn size_of<T, U>() -> usize; // error: intrinsic has wrong number
// of type parameters
}
@@ -19,6 +20,7 @@ Example:
#![feature(intrinsics)]
extern "rust-intrinsic" {
+ #[rustc_safe_intrinsic]
fn size_of<T>() -> usize; // ok!
}
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0161.md b/compiler/rustc_error_codes/src/error_codes/E0161.md
index ebd2c9769..643990ef1 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0161.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0161.md
@@ -3,7 +3,6 @@ A value was moved whose size was not known at compile time.
Erroneous code example:
```compile_fail,E0161
-#![feature(box_syntax)]
trait Bar {
fn f(self);
}
@@ -13,7 +12,7 @@ impl Bar for i32 {
}
fn main() {
- let b: Box<dyn Bar> = box (0 as i32);
+ let b: Box<dyn Bar> = Box::new(0i32);
b.f();
// error: cannot move a value of type dyn Bar: the size of dyn Bar cannot
// be statically determined
@@ -27,8 +26,6 @@ either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
it around as usual. Example:
```
-#![feature(box_syntax)]
-
trait Bar {
fn f(&self);
}
@@ -38,7 +35,7 @@ impl Bar for i32 {
}
fn main() {
- let b: Box<dyn Bar> = box (0 as i32);
+ let b: Box<dyn Bar> = Box::new(0i32);
b.f();
// ok!
}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0210.md b/compiler/rustc_error_codes/src/error_codes/E0210.md
index dc2fd9b0c..41263e5e3 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0210.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0210.md
@@ -76,7 +76,5 @@ Let `Ti` be the first such type.
For information on the design of the orphan rules,
see [RFC 2451] and [RFC 1023].
-For information on the design of the orphan rules, see [RFC 1023].
-
[RFC 2451]: https://rust-lang.github.io/rfcs/2451-re-rebalancing-coherence.html
[RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md
diff --git a/compiler/rustc_error_codes/src/error_codes/E0211.md b/compiler/rustc_error_codes/src/error_codes/E0211.md
index 77289f019..8c2462ebd 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0211.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0211.md
@@ -7,6 +7,7 @@ used. Erroneous code examples:
#![feature(intrinsics)]
extern "rust-intrinsic" {
+ #[rustc_safe_intrinsic]
fn size_of<T>(); // error: intrinsic has wrong type
}
@@ -42,6 +43,7 @@ For the first code example, please check the function definition. Example:
#![feature(intrinsics)]
extern "rust-intrinsic" {
+ #[rustc_safe_intrinsic]
fn size_of<T>() -> usize; // ok!
}
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md
new file mode 100644
index 000000000..08159d3f4
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0311.md
@@ -0,0 +1,42 @@
+This error occurs when there is an unsatisfied outlives bound involving an
+elided region and a generic type parameter or associated type.
+
+Erroneous code example:
+
+```compile_fail,E0311
+fn no_restriction<T>(x: &()) -> &() {
+ with_restriction::<T>(x)
+}
+
+fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
+ x
+}
+```
+
+Why doesn't this code compile? It helps to look at the lifetime bounds that are
+automatically added by the compiler. For more details see the documentation for
+[lifetime elision]( https://doc.rust-lang.org/reference/lifetime-elision.html).
+
+The compiler elides the lifetime of `x` and the return type to some arbitrary
+lifetime `'anon` in `no_restriction()`. The only information available to the
+compiler is that `'anon` is valid for the duration of the function. When
+calling `with_restriction()`, the compiler requires the completely unrelated
+type parameter `T` to outlive `'anon` because of the `T: 'a` bound in
+`with_restriction()`. This causes an error because `T` is not required to
+outlive `'anon` in `no_restriction()`.
+
+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:
+
+```
+fn no_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
+ with_restriction::<T>(x)
+}
+
+fn with_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
+ x
+}
+```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0579.md b/compiler/rustc_error_codes/src/error_codes/E0579.md
index f554242a3..e7e6fb682 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0579.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0579.md
@@ -8,9 +8,9 @@ Erroneous code example:
fn main() {
match 5u32 {
// This range is ok, albeit pointless.
- 1 .. 2 => {}
+ 1..2 => {}
// This range is empty, and the compiler can tell.
- 5 .. 5 => {} // error!
+ 5..5 => {} // error!
}
}
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0591.md b/compiler/rustc_error_codes/src/error_codes/E0591.md
index f49805d9b..6ed8370e8 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0591.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0591.md
@@ -53,8 +53,8 @@ unsafe {
```
Here, transmute is being used to convert the types of the fn arguments.
-This pattern is incorrect because, because the type of `foo` is a function
-**item** (`typeof(foo)`), which is zero-sized, and the target type (`fn()`)
+This pattern is incorrect because the type of `foo` is a function **item**
+(`typeof(foo)`), which is zero-sized, and the target type (`fn()`)
is a function pointer, which is not zero-sized.
This pattern should be rewritten. There are a few possible ways to do this:
diff --git a/compiler/rustc_error_codes/src/error_codes/E0622.md b/compiler/rustc_error_codes/src/error_codes/E0622.md
index 990a25494..3ba3ed10e 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0622.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0622.md
@@ -5,7 +5,7 @@ Erroneous code example:
```compile_fail,E0622
#![feature(intrinsics)]
extern "rust-intrinsic" {
- pub static breakpoint : fn(); // error: intrinsic must be a function
+ pub static breakpoint: fn(); // error: intrinsic must be a function
}
fn main() { unsafe { breakpoint(); } }
diff --git a/compiler/rustc_error_codes/src/error_codes/E0732.md b/compiler/rustc_error_codes/src/error_codes/E0732.md
index 7347e6654..9536fdbf0 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0732.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0732.md
@@ -3,8 +3,6 @@ An `enum` with a discriminant must specify a `#[repr(inttype)]`.
Erroneous code example:
```compile_fail,E0732
-#![feature(arbitrary_enum_discriminant)]
-
enum Enum { // error!
Unit = 1,
Tuple() = 2,
@@ -20,8 +18,6 @@ is a well-defined way to extract a variant's discriminant from a value;
for instance:
```
-#![feature(arbitrary_enum_discriminant)]
-
#[repr(u8)]
enum Enum {
Unit = 3,
diff --git a/compiler/rustc_error_codes/src/error_codes/E0743.md b/compiler/rustc_error_codes/src/error_codes/E0743.md
index ddd3136df..a19d3ef96 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0743.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0743.md
@@ -3,8 +3,6 @@ The C-variadic type `...` has been nested inside another type.
Erroneous code example:
```compile_fail,E0743
-#![feature(c_variadic)]
-
fn foo2(x: u8, y: &...) {} // error!
```
diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml
index fc84c7c86..9945f3379 100644
--- a/compiler/rustc_error_messages/Cargo.toml
+++ b/compiler/rustc_error_messages/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
fluent-bundle = "0.15.2"
diff --git a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl
index c45e045b4..03c88c6c0 100644
--- a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl
@@ -7,7 +7,9 @@ ast_lowering_use_angle_brackets = use angle brackets instead
ast_lowering_invalid_abi =
invalid ABI: found `{$abi}`
.label = invalid ABI
- .help = valid ABIs: {$valid_abis}
+ .note = invoke `{$command}` for a full list of supported calling conventions.
+
+ast_lowering_invalid_abi_suggestion = did you mean
ast_lowering_assoc_ty_parentheses =
parenthesized generic arguments cannot be used in associated type constraints
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl
new file mode 100644
index 000000000..178e1a67c
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl
@@ -0,0 +1,68 @@
+codegen_gcc_ranlib_failure =
+ Ranlib exited with code {$exit_code}
+
+codegen_gcc_linkage_const_or_mut_type =
+ must have type `*const T` or `*mut T` due to `#[linkage]` attribute
+
+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_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_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_mask_type =
+ invalid monomorphization of `{$name}` intrinsic: mask element type is `{$ty}`, expected `i_`
+
+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_mismatched_lengths =
+ invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}`
+
+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_operation =
+ invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}`
diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
new file mode 100644
index 000000000..966a421bc
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
@@ -0,0 +1,121 @@
+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_symbol_file_write_failure = failed to write symbols file: {$error}
+
+codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented yet for ld64
+
+codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for current linker
+
+codegen_ssa_L4Bender_exporting_symbols_unimplemented = exporting symbols not implemented yet for L4Bender
+
+codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
+
+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_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_incompatible_linking_modifiers = the linking modifiers `+bundle` and `+whole-archive` are not compatible with each other 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_rlib_missing_format = could not find formats for rlibs
+
+codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, found rmeta (metadata) file
+
+codegen_ssa_rlib_not_found = could not find rlib for: `{$crate_name}`
+
+codegen_ssa_rlib_incompatible_dependency_formats = `{$ty1}` and `{$ty2}` do not have equivalent dependency formats (`{$list1}` vs `{$list2}`)
+
+codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status}
+
+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_specify_libraries_to_link = use the `-l` flag to specify native libraries to link
+
+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_thorin_read_input_failure = failed to read input file
+
+codegen_ssa_thorin_parse_input_file_kind = failed to parse input file kind
+
+codegen_ssa_thorin_parse_input_object_file = failed to parse input object file
+
+codegen_ssa_thorin_parse_input_archive_file = failed to parse input archive file
+
+codegen_ssa_thorin_parse_archive_member = failed to parse archive member
+
+codegen_ssa_thorin_invalid_input_kind = input is not an archive or elf object
+
+codegen_ssa_thorin_decompress_data = failed to decompress compressed section
+
+codegen_ssa_thorin_section_without_name = section without name at offset {$offset}
+
+codegen_ssa_thorin_relocation_with_invalid_symbol = relocation with invalid symbol for section `{$section}` at offset {$offset}
+
+codegen_ssa_thorin_multiple_relocations = multiple relocations for section `{$section}` at offset {$offset}
+
+codegen_ssa_thorin_unsupported_relocation = unsupported relocation for section {$section} at offset {$offset}
+
+codegen_ssa_thorin_missing_dwo_name = missing path attribute to DWARF object ({$id})
+
+codegen_ssa_thorin_no_compilation_units = input object has no compilation units
+
+codegen_ssa_thorin_no_die = no top-level debugging information entry in compilation/type unit
+
+codegen_ssa_thorin_top_level_die_not_unit = top-level debugging information entry is not a compilation/type unit
+
+codegen_ssa_thorin_missing_required_section = input object missing required section `{$section}`
+
+codegen_ssa_thorin_parse_unit_abbreviations = failed to parse unit abbreviations
+
+codegen_ssa_thorin_parse_unit_attribute = failed to parse unit attribute
+
+codegen_ssa_thorin_parse_unit_header = failed to parse unit header
+
+codegen_ssa_thorin_parse_unit = failed to parse unit
+
+codegen_ssa_thorin_incompatible_index_version = incompatible `{$section}` index version: found version {$actual}, expected version {$format}
+
+codegen_ssa_thorin_offset_at_index = read offset at index {$index} of `.debug_str_offsets.dwo` section
+
+codegen_ssa_thorin_str_at_offset = read string at offset {$offset} of `.debug_str.dwo` section
+
+codegen_ssa_thorin_parse_index = failed to parse `{$section}` index section
+
+codegen_ssa_thorin_unit_not_in_index = unit {$unit} from input package is not in its index
+
+codegen_ssa_thorin_row_not_in_index = row {$row} found in index's hash table not present in index
+
+codegen_ssa_thorin_section_not_in_row = section not found in unit's row in index
+
+codegen_ssa_thorin_empty_unit = unit {$unit} in input DWARF object with no data
+
+codegen_ssa_thorin_multiple_debug_info_section = multiple `.debug_info.dwo` sections
+
+codegen_ssa_thorin_multiple_debug_types_section = multiple `.debug_types.dwo` sections in a package
+
+codegen_ssa_thorin_not_split_unit = regular compilation unit in object (missing dwo identifier)
+
+codegen_ssa_thorin_duplicate_unit = duplicate split compilation unit ({$unit})
+
+codegen_ssa_thorin_missing_referenced_unit = unit {$unit} referenced by executable was not found
+
+codegen_ssa_thorin_not_output_object_created = no output object was created from inputs
+
+codegen_ssa_thorin_mixed_input_encodings = input objects haved mixed encodings
+
+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}
diff --git a/compiler/rustc_error_messages/locales/en-US/compiletest.ftl b/compiler/rustc_error_messages/locales/en-US/compiletest.ftl
new file mode 100644
index 000000000..55061fbce
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/compiletest.ftl
@@ -0,0 +1,5 @@
+compiletest_example = this is an example message used in testing
+ .note = with a note
+ .help = with a help
+ .suggestion = with a suggestion
+ .label = with a label
diff --git a/compiler/rustc_error_messages/locales/en-US/errors.ftl b/compiler/rustc_error_messages/locales/en-US/errors.ftl
new file mode 100644
index 000000000..429bdd277
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/errors.ftl
@@ -0,0 +1,13 @@
+errors_target_invalid_address_space = invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err}
+
+errors_target_invalid_bits = invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err}
+
+errors_target_missing_alignment = missing alignment for `{$cause}` in "data-layout"
+
+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_size = {$err}
diff --git a/compiler/rustc_error_messages/locales/en-US/typeck.ftl b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
index 272731d99..74088f4df 100644
--- a/compiler/rustc_error_messages/locales/en-US/typeck.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
@@ -1,101 +1,101 @@
-typeck_field_multiply_specified_in_initializer =
+hir_analysis_field_multiply_specified_in_initializer =
field `{$ident}` specified more than once
.label = used more than once
.previous_use_label = first use of `{$ident}`
-typeck_unrecognized_atomic_operation =
+hir_analysis_unrecognized_atomic_operation =
unrecognized atomic operation function: `{$op}`
.label = unrecognized atomic operation
-typeck_wrong_number_of_generic_arguments_to_intrinsic =
+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
}
-typeck_unrecognized_intrinsic_function =
+hir_analysis_unrecognized_intrinsic_function =
unrecognized intrinsic function: `{$name}`
.label = unrecognized intrinsic
-typeck_lifetimes_or_bounds_mismatch_on_trait =
+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
-typeck_drop_impl_on_wrong_item =
+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
-typeck_field_already_declared =
+hir_analysis_field_already_declared =
field `{$field_name}` is already declared
.label = field already declared
.previous_decl_label = `{$field_name}` first declared here
-typeck_copy_impl_on_type_with_dtor =
+hir_analysis_copy_impl_on_type_with_dtor =
the trait `Copy` may not be implemented for this type; the type has a destructor
.label = `Copy` not allowed on types with destructors
-typeck_multiple_relaxed_default_bounds =
+hir_analysis_multiple_relaxed_default_bounds =
type parameter has more than one relaxed default bound, only one is supported
-typeck_copy_impl_on_non_adt =
+hir_analysis_copy_impl_on_non_adt =
the trait `Copy` may not be implemented for this type
.label = type is not a structure or enumeration
-typeck_trait_object_declared_with_no_traits =
+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
-typeck_ambiguous_lifetime_bound =
+hir_analysis_ambiguous_lifetime_bound =
ambiguous lifetime bound, explicit lifetime bound required
-typeck_assoc_type_binding_not_allowed =
+hir_analysis_assoc_type_binding_not_allowed =
associated type bindings are not allowed here
.label = associated type not allowed here
-typeck_functional_record_update_on_non_struct =
+hir_analysis_functional_record_update_on_non_struct =
functional record update syntax requires a struct
-typeck_typeof_reserved_keyword_used =
+hir_analysis_typeof_reserved_keyword_used =
`typeof` is a reserved keyword but unimplemented
.suggestion = consider replacing `typeof(...)` with an actual type
.label = reserved keyword
-typeck_return_stmt_outside_of_fn_body =
+hir_analysis_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
-typeck_yield_expr_outside_of_generator =
+hir_analysis_yield_expr_outside_of_generator =
yield expression outside of generator literal
-typeck_struct_expr_non_exhaustive =
+hir_analysis_struct_expr_non_exhaustive =
cannot create non-exhaustive {$what} using struct expression
-typeck_method_call_on_unknown_type =
+hir_analysis_method_call_on_unknown_type =
the type of this value must be known to call a method on a raw pointer on it
-typeck_value_of_associated_struct_already_specified =
+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
-typeck_address_of_temporary_taken = cannot take address of a temporary
+hir_analysis_address_of_temporary_taken = cannot take address of a temporary
.label = temporary value
-typeck_add_return_type_add = try adding a return type
+hir_analysis_add_return_type_add = try adding a return type
-typeck_add_return_type_missing_here = a return type might be missing here
+hir_analysis_add_return_type_missing_here = a return type might be missing here
-typeck_expected_default_return_type = expected `()` because of default return type
+hir_analysis_expected_default_return_type = expected `()` because of default return type
-typeck_expected_return_type = expected `{$expected}` because of return type
+hir_analysis_expected_return_type = expected `{$expected}` because of return type
-typeck_unconstrained_opaque_type = unconstrained opaque type
- .note = `{$name}` must be used in combination with a concrete type within the same module
+hir_analysis_unconstrained_opaque_type = unconstrained opaque type
+ .note = `{$name}` must be used in combination with a concrete type within the same {$what}
-typeck_missing_type_params =
+hir_analysis_missing_type_params =
the type {$parameterCount ->
[one] parameter
*[other] parameters
@@ -117,19 +117,36 @@ typeck_missing_type_params =
} to {$parameters}
.note = because of the default `Self` reference, type parameters must be specified on object types
-typeck_manual_implementation =
+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
-typeck_substs_on_overridden_impl = could not resolve substs on overridden impl
+hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl
-typeck_unused_extern_crate =
+hir_analysis_unused_extern_crate =
unused extern crate
.suggestion = remove it
-typeck_extern_crate_not_idiomatic =
+hir_analysis_extern_crate_not_idiomatic =
`extern crate` is not idiomatic in the new edition
.suggestion = convert it to a `{$msg_code}`
-typeck_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
+hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
+
+hir_analysis_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
+
+hir_analysis_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
+
+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
diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl
index 65371a285..18b3408b0 100644
--- a/compiler/rustc_error_messages/locales/en-US/infer.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl
@@ -164,7 +164,9 @@ infer_region_explanation = {$pref_kind ->
}
infer_mismatched_static_lifetime = incompatible lifetime on type
-infer_msl_impl_note = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
+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
diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl
index 7f9918e4f..7e28f22c0 100644
--- a/compiler/rustc_error_messages/locales/en-US/lint.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl
@@ -51,7 +51,7 @@ lint_non_existant_doc_keyword = found non-existing keyword `{$keyword}` used in
.help = only existing keywords are allowed in core/std
lint_diag_out_of_impl =
- diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls
+ diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
lint_untranslatable_diag = diagnostics should be created using translatable messages
@@ -433,3 +433,8 @@ lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
lint_check_name_warning = {$msg}
lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
+
+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
diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_error_messages/locales/en-US/metadata.ftl
index d27100c56..08e553d9f 100644
--- a/compiler/rustc_error_messages/locales/en-US/metadata.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/metadata.ftl
@@ -165,6 +165,8 @@ metadata_failed_write_error =
metadata_missing_native_library =
could not find native static library `{$libname}`, perhaps an -L flag is missing?
+metadata_only_provide_library_name = only provide the library name `{$suggested_name}`, not the full filename
+
metadata_failed_create_tempdir =
couldn't create a temp dir: {$err}
diff --git a/compiler/rustc_error_messages/locales/en-US/middle.ftl b/compiler/rustc_error_messages/locales/en-US/middle.ftl
index ed8348864..b9e4499d4 100644
--- a/compiler/rustc_error_messages/locales/en-US/middle.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/middle.ftl
@@ -15,3 +15,15 @@ middle_previous_use_here =
middle_limit_invalid =
`limit` must be a non-negative integer
.label = {$error_str}
+
+middle_const_eval_non_int =
+ constant evaluation of enum discriminant resulted in non-integer
+
+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
diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl
index f74df3d97..13c368d1c 100644
--- a/compiler/rustc_error_messages/locales/en-US/parser.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl
@@ -47,7 +47,7 @@ parser_invalid_comparison_operator = invalid comparison operator `{$invalid}`
.spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering`
parser_invalid_logical_operator = `{$incorrect}` is not a logical operator
- .note = unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
+ .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
@@ -55,7 +55,9 @@ parser_tilde_is_not_unary_operator = `~` cannot be used as a unary operator
.suggestion = use `!` to perform bitwise not
parser_unexpected_token_after_not = unexpected {$negated_desc} after identifier
- .suggestion = use `!` to perform logical negation
+parser_unexpected_token_after_not_bitwise = use `!` to perform bitwise not
+parser_unexpected_token_after_not_logical = use `!` to perform logical negation
+parser_unexpected_token_after_not_default = use `!` to perform logical negation or bitwise not
parser_malformed_loop_label = malformed loop label
.suggestion = use the correct loop label format
@@ -69,6 +71,8 @@ parser_field_expression_with_generic = field expressions cannot have generic arg
parser_macro_invocation_with_qualified_path = macros cannot use qualified paths
parser_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
parser_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
@@ -156,3 +160,212 @@ parser_remove_let = expected pattern, found `let`
parser_use_eq_instead = unexpected `==`
.suggestion = try using `=` instead
+
+parser_use_empty_block_not_semi = expected { "`{}`" }, found `;`
+ .suggestion = try using { "`{}`" } instead
+
+parser_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
+
+parser_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
+
+parser_found_expr_would_be_stmt = expected expression, found `{$token}`
+ .label = expected expression
+
+parser_leading_plus_not_supported = leading `+` is not supported
+ .label = unexpected `+`
+ .suggestion_remove_plus = try removing the `+`
+
+parser_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
+
+parser_labeled_loop_in_break = parentheses are required around this expression to avoid confusion with a labeled break expression
+
+parser_sugg_wrap_expression_in_parentheses = wrap the expression in parentheses
+
+parser_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
+
+parser_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 = use a comma to end a `match` arm expression
+
+parser_struct_literal_not_allowed_here = struct literals are not allowed here
+ .suggestion = surround the struct literal with parentheses
+
+parser_invalid_interpolated_expression = invalid interpolated expression
+
+parser_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
+parser_octal_float_literal_not_supported = octal float literal is not supported
+parser_binary_float_literal_not_supported = binary float literal is not supported
+parser_not_supported = not supported
+
+parser_invalid_literal_suffix = suffixes on {$kind} literals are invalid
+ .label = invalid suffix `{$suffix}`
+
+parser_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
+
+parser_non_string_abi_literal = non-string ABI literal
+ .suggestion = specify the ABI with a string literal
+
+parser_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
+
+parser_incorrect_visibility_restriction = incorrect visibility restriction
+ .help = some possible visibility restrictions are:
+ `pub(crate)`: visible only on the current crate
+ `pub(super)`: visible only in the current module's parent
+ `pub(in path::to::module)`: visible only on the specified path
+ .suggestion = make this visible only to module `{$inner_str}` with `in`
+
+parser_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed
+
+parser_expected_statement_after_outer_attr = expected statement after outer attribute
+
+parser_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
+
+parser_const_let_mutually_exclusive = `const` and `let` are mutually exclusive
+ .suggestion = remove `let`
+
+parser_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
+parser_invalid_curly_in_let_else = right curly brace `{"}"}` before `else` in a `let...else` statement not allowed
+
+parser_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
+
+parser_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.)
+
+parser_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`
+
+parser_label_inner_attr_does_not_annotate_this = the inner attribute doesn't annotate this {$item}
+parser_sugg_change_inner_attr_to_outer = to annotate the {$item}, change the attribute from inner to outer style
+
+parser_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 = {parser_label_inner_attr_does_not_annotate_this}
+ .sugg_change_inner_to_outer = {parser_sugg_change_inner_attr_to_outer}
+
+parser_inner_attr_not_permitted_after_outer_attr = an inner attribute is not permitted following an outer attribute
+ .label_attr = not permitted following an outer attribute
+ .label_prev_attr = previous outer attribute
+ .label_does_not_annotate_this = {parser_label_inner_attr_does_not_annotate_this}
+ .sugg_change_inner_to_outer = {parser_sugg_change_inner_attr_to_outer}
+
+parser_inner_attr_not_permitted = an inner attribute is not permitted in this context
+ .label_does_not_annotate_this = {parser_label_inner_attr_does_not_annotate_this}
+ .sugg_change_inner_to_outer = {parser_sugg_change_inner_attr_to_outer}
+
+parser_inner_attr_explanation = inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
+parser_outer_attr_explanation = outer attributes, like `#[test]`, annotate the item following them
+
+parser_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
+
+parser_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token}`
+parser_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token}`
+parser_expected_identifier_found_reserved_keyword_str = expected identifier, found reserved keyword `{$token}`
+parser_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token}`
+parser_expected_identifier_found_str = expected identifier, found `{$token}`
+
+parser_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier
+parser_expected_identifier_found_keyword = expected identifier, found keyword
+parser_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword
+parser_expected_identifier_found_doc_comment = expected identifier, found doc comment
+parser_expected_identifier = expected identifier
+
+parser_sugg_escape_to_use_as_identifier = escape `{$ident_name}` to use it as an identifier
+
+parser_sugg_remove_comma = remove this comma
+
+parser_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}`
+parser_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}`
+parser_expected_semi_found_reserved_keyword_str = expected `;`, found reserved keyword `{$token}`
+parser_expected_semi_found_doc_comment_str = expected `;`, found doc comment `{$token}`
+parser_expected_semi_found_str = expected `;`, found `{$token}`
+
+parser_sugg_change_this_to_semi = change this to `;`
+parser_sugg_add_semi = add `;` here
+parser_label_unexpected_token = unexpected token
+
+parser_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
+ }
+
+parser_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets
+ .suggestion = surround the type parameters with angle brackets
+
+parser_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
+parser_sugg_turbofish_syntax = use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+
+parser_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
+
+parser_unexpected_parentheses_in_for_head = unexpected parentheses surrounding `for` loop head
+ .suggestion = remove parentheses in `for` loop
+
+parser_doc_comment_on_param_type = documentation comments cannot be applied to a function parameter's type
+ .label = doc comments are not allowed here
+
+parser_attribute_on_param_type = attributes cannot be applied to a function parameter's type
+ .label = attributes are not allowed here
+
+parser_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
+
+parser_self_param_not_first = unexpected `self` parameter in function
+ .label = must be the first parameter of an associated function
+
+parser_const_generic_without_braces = expressions must be enclosed in braces to be used as const generic arguments
+ .suggestion = enclose the `const` expression in braces
+
+parser_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`
+
+parser_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
+
+parser_async_move_order_incorrect = the order of `move` and `async` is incorrect
+ .suggestion = try switching the order
+
+parser_double_colon_in_bound = expected `:` followed by trait or lifetime
+ .suggestion = use single colon
diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index 556a6452f..4bc6bd9fb 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -10,88 +10,119 @@ passes_outer_crate_level_attr =
passes_inner_crate_level_attr =
crate-level attribute should be in the root module
-passes_ignored_attr_with_macro = `#[{$sym}]` is ignored on struct fields, match arms and macro defs
+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_ignored_attr = `#[{$sym}]` is ignored on struct fields and match arms
+passes_ignored_attr =
+ `#[{$sym}]` is ignored on struct fields and match arms
.warn = {-passes_previously_accepted}
.note = {-passes_see_issue(issue: "80564")}
-passes_inline_ignored_function_prototype = `#[inline]` is ignored on function prototypes
+passes_inline_ignored_function_prototype =
+ `#[inline]` is ignored on function prototypes
-passes_inline_ignored_constants = `#[inline]` is ignored on constants
+passes_inline_ignored_constants =
+ `#[inline]` is ignored on constants
.warn = {-passes_previously_accepted}
.note = {-passes_see_issue(issue: "65833")}
-passes_inline_not_fn_or_closure = attribute should be applied to function or closure
+passes_inline_not_fn_or_closure =
+ attribute should be applied to function or closure
.label = not a function or closure
-passes_no_coverage_ignored_function_prototype = `#[no_coverage]` is ignored on function prototypes
+passes_no_coverage_ignored_function_prototype =
+ `#[no_coverage]` is ignored on function prototypes
passes_no_coverage_propagate =
`#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
-passes_no_coverage_fn_defn = `#[no_coverage]` may only be applied to function definitions
+passes_no_coverage_fn_defn =
+ `#[no_coverage]` may only be applied to function definitions
-passes_no_coverage_not_coverable = `#[no_coverage]` must be applied to coverable code
+passes_no_coverage_not_coverable =
+ `#[no_coverage]` must be applied to coverable code
.label = not coverable code
-passes_should_be_applied_to_fn = attribute should be applied to a function definition
+passes_should_be_applied_to_fn =
+ attribute should be applied to a function definition
.label = not a function definition
-passes_naked_tracked_caller = cannot use `#[track_caller]` with `#[naked]`
+passes_naked_tracked_caller =
+ cannot use `#[track_caller]` with `#[naked]`
-passes_should_be_applied_to_struct_enum = attribute should be applied to a struct or enum
+passes_should_be_applied_to_struct_enum =
+ attribute should be applied to a struct or enum
.label = not a struct or enum
-passes_should_be_applied_to_trait = attribute should be applied to a trait
+passes_should_be_applied_to_trait =
+ attribute should be applied to a trait
.label = not a trait
-passes_target_feature_on_statement = {passes_should_be_applied_to_fn}
+passes_target_feature_on_statement =
+ {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
+passes_should_be_applied_to_static =
+ attribute should be applied to a static
.label = not a static
-passes_doc_expect_str = doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")]
+passes_doc_expect_str =
+ doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")]
-passes_doc_alias_empty = {$attr_str} attribute cannot have empty value
+passes_doc_alias_empty =
+ {$attr_str} attribute cannot have empty value
-passes_doc_alias_bad_char = {$char_} character isn't allowed in {$attr_str}
+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_start_end =
+ {$attr_str} cannot start or end with ' '
-passes_doc_alias_bad_location = {$attr_str} isn't allowed on {$location}
+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_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_not_string_literal =
+ `#[doc(alias("a"))]` expects string literals
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_keyword_empty_mod =
+ `#[doc(keyword = "...")]` should be used on empty modules
-passes_doc_keyword_not_mod = `#[doc(keyword = "...")]` should be used on modules
+passes_doc_keyword_not_mod =
+ `#[doc(keyword = "...")]` should be used on modules
-passes_doc_keyword_invalid_ident = `{$doc_keyword}` is not a valid identifier
+passes_doc_keyword_invalid_ident =
+ `{$doc_keyword}` is not a valid identifier
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_keyword_only_impl =
+ `#[doc(keyword = "...")]` should be used on impl blocks
-passes_doc_inline_conflict_first = this attribute...
-passes_doc_inline_conflict_second = ...conflicts with this attribute
-passes_doc_inline_conflict = conflicting doc inlining attributes
+passes_doc_inline_conflict_first =
+ this attribute...
+
+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
+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
@@ -99,30 +130,42 @@ passes_doc_inline_only_use = this attribute can only be applied to a `use` item
passes_doc_attr_not_crate_level =
`#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute
-passes_attr_crate_level = this attribute can only be applied at the crate level
+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_test_unknown = unknown `doc(test)` attribute `{$path}`
+passes_doc_test_unknown =
+ unknown `doc(test)` attribute `{$path}`
+
+passes_doc_test_takes_list =
+ `#[doc(test(...)]` takes a list of attributes
-passes_doc_test_takes_list = `#[doc(test(...)]` takes a list of attributes
+passes_doc_primitive =
+ `doc(primitive)` should never have been stable
-passes_doc_primitive = `doc(primitive)` should never have been stable
+passes_doc_cfg_hide_takes_list =
+ `#[doc(cfg_hide(...)]` takes a list of attributes
-passes_doc_test_unknown_any = unknown `doc` attribute `{$path}`
+passes_doc_test_unknown_any =
+ unknown `doc` attribute `{$path}`
-passes_doc_test_unknown_spotlight = unknown `doc` attribute `{$path}`
+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}`
+passes_doc_test_unknown_include =
+ unknown `doc` attribute `{$path}`
.suggestion = use `doc = include_str!` instead
-passes_doc_invalid = invalid `doc` attribute
+passes_doc_invalid =
+ invalid `doc` attribute
-passes_pass_by_value = `pass_by_value` attribute should be applied to a struct, enum or type alias
+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_allow_incoherent_impl =
@@ -137,42 +180,54 @@ 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_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
+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_cold = {passes_should_be_applied_to_fn}
+passes_cold =
+ {passes_should_be_applied_to_fn}
.warn = {-passes_previously_accepted}
.label = {passes_should_be_applied_to_fn.label}
-passes_link = attribute should be applied to an `extern` block with non-Rust ABI
+passes_link =
+ attribute should be applied to an `extern` block with non-Rust ABI
.warn = {-passes_previously_accepted}
.label = not an `extern` block
-passes_link_name = attribute should be applied to a foreign function or static
+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_no_link = attribute should be applied to an `extern crate` item
+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
+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
+passes_rustc_layout_scalar_valid_range_not_struct =
+ attribute should be applied to a struct
.label = not a struct
-passes_rustc_layout_scalar_valid_range_arg = expected exactly one integer literal argument
+passes_rustc_layout_scalar_valid_range_arg =
+ expected exactly one integer literal argument
-passes_rustc_legacy_const_generics_only = #[rustc_legacy_const_generics] functions must only have const generics
+passes_rustc_legacy_const_generics_only =
+ #[rustc_legacy_const_generics] functions must only have const generics
.label = non-const generic parameter
-passes_rustc_legacy_const_generics_index = #[rustc_legacy_const_generics] must have one index for each generic parameter
+passes_rustc_legacy_const_generics_index =
+ #[rustc_legacy_const_generics] must have one index for each generic parameter
.label = generic parameters
-passes_rustc_legacy_const_generics_index_exceed = index exceeds number of arguments
+passes_rustc_legacy_const_generics_index_exceed =
+ index exceeds number of arguments
.label = there {$arg_count ->
[one] is
*[other] are
@@ -181,90 +236,438 @@ passes_rustc_legacy_const_generics_index_exceed = index exceeds number of argume
*[other] arguments
}
-passes_rustc_legacy_const_generics_index_negative = arguments should be non-negative integers
+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_rustc_dirty_clean =
+ attribute requires -Z query-dep-graph to be enabled
-passes_link_section = attribute should be applied to a function or static
+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}
+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_no_mangle = attribute should be applied to a free function, impl method or static
+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_repr_ident = meta item in `repr` must be an identifier
+passes_repr_ident =
+ meta item in `repr` must be an identifier
-passes_repr_conflicting = conflicting representation hints
+passes_repr_conflicting =
+ conflicting representation hints
-passes_used_static = attribute must be applied to a `static` variable
+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_used_compiler_linker =
+ `used(compiler)` and `used(linker)` can't be used together
-passes_allow_internal_unstable = attribute should be applied to a macro
+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_placement =
+ attribute should be applied to a module
-passes_debug_visualizer_invalid = invalid argument
+passes_debug_visualizer_invalid =
+ invalid argument
.note_1 = expected: `natvis_file = "..."`
.note_2 = OR
.note_3 = expected: `gdb_script_file = "..."`
-passes_rustc_allow_const_fn_unstable = attribute should be applied to `const fn`
+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
+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_const_trait =
+ attribute should be applied to a trait
-passes_stability_promotable = attribute cannot be applied to an expression
+passes_stability_promotable =
+ attribute cannot be applied to an expression
-passes_deprecated = attribute is ignored here
+passes_deprecated =
+ attribute is ignored here
-passes_macro_use = `#[{$name}]` only has an effect on `extern crate` and modules
+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_macro_export =
+ `#[macro_export]` only has an effect on macro definitions
-passes_plugin_registrar = `#[plugin_registrar]` only has an effect on functions
+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_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_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
-passes_unused = unused attribute
+passes_unused =
+ unused attribute
.suggestion = remove this attribute
-passes_non_exported_macro_invalid_attrs = attribute should be applied to function or closure
+passes_non_exported_macro_invalid_attrs =
+ attribute should be applied to function or closure
.label = not a function or closure
-passes_unused_duplicate = unused attribute
+passes_unused_duplicate =
+ unused attribute
.suggestion = remove this attribute
.note = attribute also specified here
.warn = {-passes_previously_accepted}
-passes_unused_multiple = multiple `{$name}` attributes
+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
+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
+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
+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
+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_alloc_func_required =
+ `#[alloc_error_handler]` function required, but not found
+
+passes_missing_alloc_error_handler =
+ use `#![feature(default_alloc_error_handler)]` for a default error handler
+
+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_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 =
+ duplicate diagnostic item found: `{$name}`.
+
+passes_duplicate_diagnostic_item_in_crate =
+ duplicate diagnostic item in crate `{$crate_name}`: `{$name}`.
+
+passes_diagnostic_item_first_defined =
+ the diagnostic item is first defined here
+ .note = the diagnostic item is first defined in crate `{$orig_crate_name}`.
+
+passes_abi =
+ abi: {$abi}
+
+passes_align =
+ align: {$align}
+
+passes_size =
+ size: {$size}
+
+passes_homogeneous_aggregate =
+ homogeneous_aggregate: {$homogeneous_aggregate}
+
+passes_layout_of =
+ layout_of({$normalized_ty}) = {$ty_layout}
+
+passes_unrecognized_field =
+ unrecognized field name `{$name}`
+
+passes_layout =
+ layout error: {$layout_error}
+
+passes_feature_stable_twice =
+ feature `{$feature}` is declared stable since {$since}, but was previously declared stable since {$prev_since}
+
+passes_feature_previously_declared =
+ feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared}
+
+passes_expr_not_allowed_in_context =
+ {$expr} is not allowed in a `{$context}`
+
+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_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_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_break_inside_closure =
+ `{$name}` inside of a closure
+ .label = cannot `{$name}` inside of a closure
+ .closure_label = enclosing closure
+
+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_outside_loop =
+ `{$name}` outside of a loop
+ .label = cannot `{$name}` outside of a loop
+
+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_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_cannot_inline_naked_function =
+ naked functions cannot be inlined
+
+passes_undefined_naked_function_abi =
+ Rust ABI is unsupported in naked functions
+
+passes_no_patterns =
+ patterns not allowed in naked function parameters
+
+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_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}
+
+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_attr_only_on_root_main =
+ `{$attr}` attribute can only be used on root `fn main()`
+
+passes_attr_only_in_functions =
+ `{$attr}` attribute can only be used on functions
+
+passes_multiple_rustc_main =
+ multiple functions with a `#[rustc_main]` attribute
+ .first = first `#[rustc_main]` function
+ .additional = additional `#[rustc_main]` function
+
+passes_multiple_start_functions =
+ multiple `start` functions
+ .label = multiple `start` functions
+ .previous = previous `#[start]` function here
+
+passes_extern_main =
+ the `main` function cannot be declared in an `extern` block
+
+passes_unix_sigpipe_values =
+ valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
+
+passes_no_main_function =
+ `main` function not found in crate `{$crate_name}`
+ .here_is_main = here is a function named `main`
+ .one_or_more_possible_main = you have one or more functions named `main` not defined at the crate level
+ .consider_moving_main = consider moving the `main` function definitions
+ .main_must_be_defined_at_crate = the main function must be defined at the crate level{$has_filename ->
+ [true] {" "}(in `{$filename}`)
+ *[false] {""}
+ }
+ .consider_adding_main_to_file = consider adding a `main` function to `{$filename}`
+ .consider_adding_main_at_crate = consider adding a `main` function at the crate level
+ .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_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_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_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_useless_assignment =
+ useless assignment of {$is_field_assign ->
+ [true] field
+ *[false] variable
+ } of type `{$ty}` to itself
+
+passes_only_has_effect_on =
+ `#[{$attr_name}]` only has an effect on {$target_name ->
+ [function] functions
+ [module] modules
+ [implementation_block] implementation blocks
+ *[unspecified] (unspecified--this is a compiler bug)
+ }
+
+passes_object_lifetime_err =
+ {$repr}
+
+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_attr_application_enum =
+ attribute should be applied to an enum
+ .label = not an enum
+
+passes_attr_application_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_attr_application_struct_enum_union =
+ attribute should be applied to a struct, enum, or union
+ .label = not a struct, enum, or union
+
+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_transparent_incompatible =
+ transparent {$target} cannot have other repr hints
+
+passes_deprecated_attribute =
+ deprecated attribute must be paired with either stable or unstable attribute
+
+passes_useless_stability =
+ this stability annotation is useless
+ .label = useless stability annotation
+ .item = the stability attribute annotates this item
+
+passes_invalid_stability =
+ invalid stability version found
+ .label = invalid stability version
+ .item = the stability attribute annotates this item
+
+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_invalid_deprecation_version =
+ invalid deprecation version found
+ .label = invalid deprecation version
+ .item = the stability attribute annotates this item
+
+passes_missing_stability_attr =
+ {$descr} has missing stability attribute
+
+passes_missing_const_stab_attr =
+ {$descr} has missing const stability attribute
+
+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_unknown_feature =
+ unknown feature `{$feature}`
+
+passes_implied_feature_not_exist =
+ feature `{$implied_by}` implying `{$feature}` does not exist
+
+passes_duplicate_feature_err =
+ the feature `{$feature}` has already been declared
+
+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
diff --git a/compiler/rustc_error_messages/locales/en-US/privacy.ftl b/compiler/rustc_error_messages/locales/en-US/privacy.ftl
index da987152f..a26d1b2b3 100644
--- a/compiler/rustc_error_messages/locales/en-US/privacy.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/privacy.ftl
@@ -11,7 +11,7 @@ privacy_in_public_interface = {$vis_descr} {$kind} `{$descr}` in public interfac
.label = can't leak {$vis_descr} {$kind}
.visibility_label = `{$descr}` declared as {$vis_descr}
-privacy_report_access_level = {$descr}
+privacy_report_effective_visibility = {$descr}
privacy_from_private_dep_in_public_interface =
{$kind} `{$descr}` from private dependency '{$krate}' in public interface
diff --git a/compiler/rustc_error_messages/locales/en-US/query_system.ftl b/compiler/rustc_error_messages/locales/en-US/query_system.ftl
index 167704e46..870e82403 100644
--- a/compiler/rustc_error_messages/locales/en-US/query_system.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/query_system.ftl
@@ -12,6 +12,8 @@ query_system_cycle_usage = cycle used when {$usage}
query_system_cycle_stack_single = ...which immediately requires {$stack_bottom} again
+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
@@ -23,3 +25,6 @@ query_system_cycle_recursive_trait_alias = trait aliases cannot be recursive
query_system_cycle_which_requires = ...which requires {$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}
diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl
index 76cae3c81..e22779230 100644
--- a/compiler/rustc_error_messages/locales/en-US/session.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/session.ftl
@@ -39,20 +39,6 @@ session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination`
session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5
-session_target_invalid_address_space = invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err}
-
-session_target_invalid_bits = invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err}
-
-session_target_missing_alignment = missing alignment for `{$cause}` in "data-layout"
-
-session_target_invalid_alignment = invalid alignment for `{$cause}` in "data-layout": {$err}
-
-session_target_inconsistent_architecture = inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}`
-
-session_target_inconsistent_pointer_width = inconsistent target specification: "data-layout" claims pointers are {$pointer_size}-bit, while "target-pointer-width" is `{$target}`
-
-session_target_invalid_bits_size = {$err}
-
session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored
session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform
@@ -66,3 +52,9 @@ session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has
session_crate_name_empty = crate name must not be empty
session_invalid_character_in_create_name = invalid character `{$character}` in crate name: `{$crate_name}`
+
+session_expr_parentheses_needed = parentheses are required to parse this as an expression
+
+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
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index b6e0f3faa..9465051dd 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -35,32 +35,38 @@ pub use unic_langid::{langid, LanguageIdentifier};
// Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
fluent_messages! {
+ // tidy-alphabetical-start
ast_lowering => "../locales/en-US/ast_lowering.ftl",
ast_passes => "../locales/en-US/ast_passes.ftl",
attr => "../locales/en-US/attr.ftl",
borrowck => "../locales/en-US/borrowck.ftl",
builtin_macros => "../locales/en-US/builtin_macros.ftl",
+ codegen_gcc => "../locales/en-US/codegen_gcc.ftl",
+ codegen_ssa => "../locales/en-US/codegen_ssa.ftl",
+ compiletest => "../locales/en-US/compiletest.ftl",
const_eval => "../locales/en-US/const_eval.ftl",
driver => "../locales/en-US/driver.ftl",
+ errors => "../locales/en-US/errors.ftl",
expand => "../locales/en-US/expand.ftl",
- session => "../locales/en-US/session.ftl",
- interface => "../locales/en-US/interface.ftl",
+ hir_analysis => "../locales/en-US/hir_analysis.ftl",
infer => "../locales/en-US/infer.ftl",
+ interface => "../locales/en-US/interface.ftl",
lint => "../locales/en-US/lint.ftl",
+ metadata => "../locales/en-US/metadata.ftl",
middle => "../locales/en-US/middle.ftl",
+ mir_dataflow => "../locales/en-US/mir_dataflow.ftl",
monomorphize => "../locales/en-US/monomorphize.ftl",
- metadata => "../locales/en-US/metadata.ftl",
parser => "../locales/en-US/parser.ftl",
passes => "../locales/en-US/passes.ftl",
plugin_impl => "../locales/en-US/plugin_impl.ftl",
privacy => "../locales/en-US/privacy.ftl",
query_system => "../locales/en-US/query_system.ftl",
- trait_selection => "../locales/en-US/trait_selection.ftl",
save_analysis => "../locales/en-US/save_analysis.ftl",
- ty_utils => "../locales/en-US/ty_utils.ftl",
- typeck => "../locales/en-US/typeck.ftl",
- mir_dataflow => "../locales/en-US/mir_dataflow.ftl",
+ session => "../locales/en-US/session.ftl",
symbol_mangling => "../locales/en-US/symbol_mangling.ftl",
+ trait_selection => "../locales/en-US/trait_selection.ftl",
+ ty_utils => "../locales/en-US/ty_utils.ftl",
+ // tidy-alphabetical-end
}
pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};
@@ -268,14 +274,26 @@ type FluentId = Cow<'static, str>;
/// Translatable messages for subdiagnostics are typically attributes attached to a larger Fluent
/// message so messages of this type must be combined with a `DiagnosticMessage` (using
/// `DiagnosticMessage::with_subdiagnostic_message`) before rendering. However, subdiagnostics from
-/// the `SessionSubdiagnostic` derive refer to Fluent identifiers directly.
+/// the `Subdiagnostic` derive refer to Fluent identifiers directly.
#[rustc_diagnostic_item = "SubdiagnosticMessage"]
pub enum SubdiagnosticMessage {
/// Non-translatable diagnostic message.
// FIXME(davidtwco): can a `Cow<'static, str>` be used here?
Str(String),
+ /// Translatable message which has already been translated eagerly.
+ ///
+ /// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
+ /// be instantiated multiple times with different values. As translation normally happens
+ /// immediately prior to emission, after the diagnostic and subdiagnostic derive logic has run,
+ /// the setting of diagnostic arguments in the derived code will overwrite previous variable
+ /// values and only the final value will be set when translation occurs - resulting in
+ /// incorrect diagnostics. Eager translation results in translation for a subdiagnostic
+ /// happening immediately after the subdiagnostic derive's logic has been run. This variant
+ /// stores messages which have been translated eagerly.
+ // FIXME(#100717): can a `Cow<'static, str>` be used here?
+ Eager(String),
/// Identifier of a Fluent message. Instances of this variant are generated by the
- /// `SessionSubdiagnostic` derive.
+ /// `Subdiagnostic` derive.
FluentIdentifier(FluentId),
/// Attribute of a Fluent message. Needs to be combined with a Fluent identifier to produce an
/// actual translated message. Instances of this variant are generated by the `fluent_messages`
@@ -301,8 +319,20 @@ impl<S: Into<String>> From<S> for SubdiagnosticMessage {
#[rustc_diagnostic_item = "DiagnosticMessage"]
pub enum DiagnosticMessage {
/// Non-translatable diagnostic message.
- // FIXME(davidtwco): can a `Cow<'static, str>` be used here?
+ // FIXME(#100717): can a `Cow<'static, str>` be used here?
Str(String),
+ /// Translatable message which has already been translated eagerly.
+ ///
+ /// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
+ /// be instantiated multiple times with different values. As translation normally happens
+ /// immediately prior to emission, after the diagnostic and subdiagnostic derive logic has run,
+ /// the setting of diagnostic arguments in the derived code will overwrite previous variable
+ /// values and only the final value will be set when translation occurs - resulting in
+ /// incorrect diagnostics. Eager translation results in translation for a subdiagnostic
+ /// happening immediately after the subdiagnostic derive's logic has been run. This variant
+ /// stores messages which have been translated eagerly.
+ // FIXME(#100717): can a `Cow<'static, str>` be used here?
+ Eager(String),
/// Identifier for a Fluent message (with optional attribute) corresponding to the diagnostic
/// message.
///
@@ -321,6 +351,7 @@ impl DiagnosticMessage {
pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self {
let attr = match sub {
SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s),
+ SubdiagnosticMessage::Eager(s) => return DiagnosticMessage::Eager(s),
SubdiagnosticMessage::FluentIdentifier(id) => {
return DiagnosticMessage::FluentIdentifier(id, None);
}
@@ -329,24 +360,12 @@ impl DiagnosticMessage {
match self {
DiagnosticMessage::Str(s) => DiagnosticMessage::Str(s.clone()),
+ DiagnosticMessage::Eager(s) => DiagnosticMessage::Eager(s.clone()),
DiagnosticMessage::FluentIdentifier(id, _) => {
DiagnosticMessage::FluentIdentifier(id.clone(), Some(attr))
}
}
}
-
- /// Returns the `String` contained within the `DiagnosticMessage::Str` variant, assuming that
- /// this diagnostic message is of the legacy, non-translatable variety. Panics if this
- /// assumption does not hold.
- ///
- /// Don't use this - it exists to support some places that do comparison with diagnostic
- /// strings.
- pub fn expect_str(&self) -> &str {
- match self {
- DiagnosticMessage::Str(s) => s,
- _ => panic!("expected non-translatable diagnostic message"),
- }
- }
}
/// `From` impl that enables existing diagnostic calls to functions which now take
@@ -357,6 +376,17 @@ impl<S: Into<String>> From<S> for DiagnosticMessage {
}
}
+/// A workaround for "good path" ICEs when formatting types in disables lints.
+///
+/// Delays formatting until `.into(): DiagnosticMessage` is used.
+pub struct DelayDm<F>(pub F);
+
+impl<F: FnOnce() -> String> From<DelayDm<F>> for DiagnosticMessage {
+ fn from(DelayDm(f): DelayDm<F>) -> Self {
+ DiagnosticMessage::from(f())
+ }
+}
+
/// Translating *into* a subdiagnostic message from a diagnostic message is a little strange - but
/// the subdiagnostic functions (e.g. `span_label`) take a `SubdiagnosticMessage` and the
/// subdiagnostic derive refers to typed identifiers that are `DiagnosticMessage`s, so need to be
@@ -366,6 +396,7 @@ impl Into<SubdiagnosticMessage> for DiagnosticMessage {
fn into(self) -> SubdiagnosticMessage {
match self {
DiagnosticMessage::Str(s) => SubdiagnosticMessage::Str(s),
+ DiagnosticMessage::Eager(s) => SubdiagnosticMessage::Eager(s),
DiagnosticMessage::FluentIdentifier(id, None) => {
SubdiagnosticMessage::FluentIdentifier(id)
}
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index c36ca11fa..7803a0792 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -4,10 +4,11 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
tracing = "0.1"
+rustc_ast = { path = "../rustc_ast" }
+rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_error_messages = { path = "../rustc_error_messages" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index b32fc3c71..f14b8ee32 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -7,7 +7,7 @@
use crate::emitter::FileWithAnnotatedLines;
use crate::snippet::Line;
-use crate::translation::Translate;
+use crate::translation::{to_fluent_args, Translate};
use crate::{
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle,
LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic,
@@ -46,7 +46,7 @@ impl Translate for AnnotateSnippetEmitterWriter {
impl Emitter for AnnotateSnippetEmitterWriter {
/// The entry point for the diagnostics generation
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
- let fluent_args = self.to_fluent_args(diag.args());
+ let fluent_args = to_fluent_args(diag.args());
let mut children = diag.children.clone();
let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index a774b52c8..23f29a24f 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -1,21 +1,17 @@
use crate::snippet::Style;
use crate::{
- CodeSuggestion, DiagnosticMessage, EmissionGuarantee, Level, LintDiagnosticBuilder, MultiSpan,
+ CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Level, MultiSpan,
SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle,
};
use rustc_data_structures::fx::FxHashMap;
use rustc_error_messages::FluentValue;
-use rustc_hir as hir;
use rustc_lint_defs::{Applicability, LintExpectationId};
use rustc_span::edition::LATEST_STABLE_EDITION;
-use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
-use rustc_span::{edition::Edition, Span, DUMMY_SP};
-use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
+use rustc_span::symbol::Symbol;
+use rustc_span::{Span, DUMMY_SP};
use std::borrow::Cow;
use std::fmt;
use std::hash::{Hash, Hasher};
-use std::num::ParseIntError;
-use std::path::{Path, PathBuf};
/// Error type for `Diagnostic`'s `suggestions` field, indicating that
/// `.disable_suggestions()` was called on the `Diagnostic`.
@@ -25,7 +21,11 @@ pub struct SuggestionsDisabled;
/// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of
/// `DiagnosticArg` are converted to `FluentArgs` (consuming the collection) at the start of
/// diagnostic emission.
-pub type DiagnosticArg<'source> = (Cow<'source, str>, DiagnosticArgValue<'source>);
+pub type DiagnosticArg<'iter, 'source> =
+ (&'iter DiagnosticArgName<'source>, &'iter DiagnosticArgValue<'source>);
+
+/// Name of a diagnostic argument.
+pub type DiagnosticArgName<'source> = Cow<'source, str>;
/// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted
/// to a `FluentValue` by the emitter to be used in diagnostic translation.
@@ -35,7 +35,7 @@ pub enum DiagnosticArgValue<'source> {
Number(usize),
}
-/// Converts a value of a type into a `DiagnosticArg` (typically a field of a `SessionDiagnostic`
+/// Converts a value of a type into a `DiagnosticArg` (typically a field of an `IntoDiagnostic`
/// struct). Implemented as a custom trait rather than `From` so that it is implemented on the type
/// being converted rather than on `DiagnosticArgValue`, which enables types from other `rustc_*`
/// crates to implement this.
@@ -43,119 +43,6 @@ pub trait IntoDiagnosticArg {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>;
}
-pub struct DiagnosticArgFromDisplay<'a>(pub &'a dyn fmt::Display);
-
-impl IntoDiagnosticArg for DiagnosticArgFromDisplay<'_> {
- fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
- self.0.to_string().into_diagnostic_arg()
- }
-}
-
-impl<'a> From<&'a dyn fmt::Display> for DiagnosticArgFromDisplay<'a> {
- fn from(t: &'a dyn fmt::Display) -> Self {
- DiagnosticArgFromDisplay(t)
- }
-}
-
-impl<'a, T: fmt::Display> From<&'a T> for DiagnosticArgFromDisplay<'a> {
- fn from(t: &'a T) -> Self {
- DiagnosticArgFromDisplay(t)
- }
-}
-
-macro_rules! into_diagnostic_arg_using_display {
- ($( $ty:ty ),+ $(,)?) => {
- $(
- impl IntoDiagnosticArg for $ty {
- fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
- self.to_string().into_diagnostic_arg()
- }
- }
- )+
- }
-}
-
-into_diagnostic_arg_using_display!(
- i8,
- u8,
- i16,
- u16,
- i32,
- u32,
- i64,
- u64,
- i128,
- u128,
- std::io::Error,
- std::num::NonZeroU32,
- hir::Target,
- Edition,
- Ident,
- MacroRulesNormalizedIdent,
- ParseIntError,
- StackProtector,
- &TargetTriple,
- SplitDebuginfo
-);
-
-impl IntoDiagnosticArg for bool {
- fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
- if self {
- DiagnosticArgValue::Str(Cow::Borrowed("true"))
- } else {
- DiagnosticArgValue::Str(Cow::Borrowed("false"))
- }
- }
-}
-
-impl IntoDiagnosticArg for char {
- fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
- DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self)))
- }
-}
-
-impl IntoDiagnosticArg for Symbol {
- fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
- self.to_ident_string().into_diagnostic_arg()
- }
-}
-
-impl<'a> IntoDiagnosticArg for &'a str {
- fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
- self.to_string().into_diagnostic_arg()
- }
-}
-
-impl IntoDiagnosticArg for String {
- fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
- DiagnosticArgValue::Str(Cow::Owned(self))
- }
-}
-
-impl<'a> IntoDiagnosticArg for &'a Path {
- fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
- DiagnosticArgValue::Str(Cow::Owned(self.display().to_string()))
- }
-}
-
-impl IntoDiagnosticArg for PathBuf {
- fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
- DiagnosticArgValue::Str(Cow::Owned(self.display().to_string()))
- }
-}
-
-impl IntoDiagnosticArg for usize {
- fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
- DiagnosticArgValue::Number(self)
- }
-}
-
-impl IntoDiagnosticArg for PanicStrategy {
- fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
- DiagnosticArgValue::Str(Cow::Owned(self.desc().to_string()))
- }
-}
-
impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> {
fn into(self) -> FluentValue<'source> {
match self {
@@ -165,22 +52,24 @@ impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> {
}
}
-impl IntoDiagnosticArg for hir::ConstContext {
- fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
- DiagnosticArgValue::Str(Cow::Borrowed(match self {
- hir::ConstContext::ConstFn => "constant function",
- hir::ConstContext::Static(_) => "static",
- hir::ConstContext::Const => "constant",
- }))
- }
-}
-
/// Trait implemented by error types. This should not be implemented manually. Instead, use
-/// `#[derive(SessionSubdiagnostic)]` -- see [rustc_macros::SessionSubdiagnostic].
-#[rustc_diagnostic_item = "AddSubdiagnostic"]
-pub trait AddSubdiagnostic {
+/// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic].
+#[cfg_attr(bootstrap, rustc_diagnostic_item = "AddSubdiagnostic")]
+#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "AddToDiagnostic")]
+pub trait AddToDiagnostic
+where
+ Self: Sized,
+{
/// Add a subdiagnostic to an existing diagnostic.
- fn add_to_diagnostic(self, diag: &mut Diagnostic);
+ fn add_to_diagnostic(self, diag: &mut Diagnostic) {
+ self.add_to_diagnostic_with(diag, |_, m| m);
+ }
+
+ /// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used
+ /// (to optionally perform eager translation).
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage;
}
/// Trait implemented by lint types. This should not be implemented manually. Instead, use
@@ -188,7 +77,12 @@ pub trait AddSubdiagnostic {
#[rustc_diagnostic_item = "DecorateLint"]
pub trait DecorateLint<'a, G: EmissionGuarantee> {
/// Decorate and emit a lint.
- fn decorate_lint(self, diag: LintDiagnosticBuilder<'a, G>);
+ fn decorate_lint<'b>(
+ self,
+ diag: &'b mut DiagnosticBuilder<'a, G>,
+ ) -> &'b mut DiagnosticBuilder<'a, G>;
+
+ fn msg(&self) -> DiagnosticMessage;
}
#[must_use]
@@ -203,7 +97,7 @@ pub struct Diagnostic {
pub span: MultiSpan,
pub children: Vec<SubDiagnostic>,
pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
- args: Vec<DiagnosticArg<'static>>,
+ args: FxHashMap<DiagnosticArgName<'static>, DiagnosticArgValue<'static>>,
/// This is not used for highlighting or rendering any error message. Rather, it can be used
/// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of
@@ -295,7 +189,7 @@ impl Diagnostic {
span: MultiSpan::new(),
children: vec![],
suggestions: Ok(vec![]),
- args: vec![],
+ args: Default::default(),
sort_span: DUMMY_SP,
is_lint: false,
}
@@ -338,9 +232,10 @@ impl Diagnostic {
// The lint index inside the attribute is manually transferred here.
let lint_index = expectation_id.get_lint_index();
expectation_id.set_lint_index(None);
- let mut stable_id = *unstable_to_stable
+ let mut stable_id = unstable_to_stable
.get(&expectation_id)
- .expect("each unstable `LintExpectationId` must have a matching stable id");
+ .expect("each unstable `LintExpectationId` must have a matching stable id")
+ .normalize();
stable_id.set_lint_index(lint_index);
*expectation_id = stable_id;
@@ -672,6 +567,11 @@ impl Diagnostic {
style: SuggestionStyle,
) -> &mut Self {
assert!(!suggestion.is_empty());
+ debug_assert!(
+ !(suggestion.iter().any(|(sp, text)| sp.is_empty() && text.is_empty())),
+ "Span must not be empty and have no suggestion"
+ );
+
self.push_suggestion(CodeSuggestion {
substitutions: vec![Substitution {
parts: suggestion
@@ -749,6 +649,10 @@ impl Diagnostic {
applicability: Applicability,
style: SuggestionStyle,
) -> &mut Self {
+ debug_assert!(
+ !(sp.is_empty() && suggestion.to_string().is_empty()),
+ "Span must not be empty and have no suggestion"
+ );
self.push_suggestion(CodeSuggestion {
substitutions: vec![Substitution {
parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
@@ -787,8 +691,32 @@ impl Diagnostic {
suggestions: impl Iterator<Item = String>,
applicability: Applicability,
) -> &mut Self {
+ self.span_suggestions_with_style(
+ sp,
+ msg,
+ suggestions,
+ applicability,
+ SuggestionStyle::ShowCode,
+ )
+ }
+
+ /// [`Diagnostic::span_suggestions()`] but you can set the [`SuggestionStyle`].
+ pub fn span_suggestions_with_style(
+ &mut self,
+ sp: Span,
+ msg: impl Into<SubdiagnosticMessage>,
+ suggestions: impl Iterator<Item = String>,
+ applicability: Applicability,
+ style: SuggestionStyle,
+ ) -> &mut Self {
let mut suggestions: Vec<_> = suggestions.collect();
suggestions.sort();
+
+ debug_assert!(
+ !(sp.is_empty() && suggestions.iter().any(|suggestion| suggestion.is_empty())),
+ "Span must not be empty and have no suggestion"
+ );
+
let substitutions = suggestions
.into_iter()
.map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] })
@@ -796,22 +724,33 @@ impl Diagnostic {
self.push_suggestion(CodeSuggestion {
substitutions,
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
- style: SuggestionStyle::ShowCode,
+ style,
applicability,
});
self
}
- /// Prints out a message with multiple suggested edits of the code.
- /// See also [`Diagnostic::span_suggestion()`].
+ /// Prints out a message with multiple suggested edits of the code, where each edit consists of
+ /// multiple parts.
+ /// See also [`Diagnostic::multipart_suggestion()`].
pub fn multipart_suggestions(
&mut self,
msg: impl Into<SubdiagnosticMessage>,
suggestions: impl Iterator<Item = Vec<(Span, String)>>,
applicability: Applicability,
) -> &mut Self {
+ let suggestions: Vec<_> = suggestions.collect();
+ debug_assert!(
+ !(suggestions
+ .iter()
+ .flat_map(|suggs| suggs)
+ .any(|(sp, suggestion)| sp.is_empty() && suggestion.is_empty())),
+ "Span must not be empty and have no suggestion"
+ );
+
self.push_suggestion(CodeSuggestion {
substitutions: suggestions
+ .into_iter()
.map(|sugg| Substitution {
parts: sugg
.into_iter()
@@ -825,6 +764,7 @@ impl Diagnostic {
});
self
}
+
/// Prints out a message with a suggested edit of the code. If the suggestion is presented
/// inline, it will only show the message and not the suggestion.
///
@@ -890,13 +830,30 @@ impl Diagnostic {
self
}
- /// Add a subdiagnostic from a type that implements `SessionSubdiagnostic` - see
- /// [rustc_macros::SessionSubdiagnostic].
- pub fn subdiagnostic(&mut self, subdiagnostic: impl AddSubdiagnostic) -> &mut Self {
+ /// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
+ /// [rustc_macros::Subdiagnostic]).
+ pub fn subdiagnostic(&mut self, subdiagnostic: impl AddToDiagnostic) -> &mut Self {
subdiagnostic.add_to_diagnostic(self);
self
}
+ /// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
+ /// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages
+ /// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of
+ /// interpolated variables).
+ pub fn eager_subdiagnostic(
+ &mut self,
+ handler: &crate::Handler,
+ subdiagnostic: impl AddToDiagnostic,
+ ) -> &mut Self {
+ subdiagnostic.add_to_diagnostic_with(self, |diag, msg| {
+ let args = diag.args();
+ let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
+ handler.eagerly_translate(msg, args)
+ });
+ self
+ }
+
pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
self.span = sp.into();
if let Some(span) = self.span.primary_span() {
@@ -929,8 +886,11 @@ impl Diagnostic {
self
}
- pub fn args(&self) -> &[DiagnosticArg<'static>] {
- &self.args
+ // Exact iteration order of diagnostic arguments shouldn't make a difference to output because
+ // they're only used in interpolation.
+ #[allow(rustc::potential_query_instability)]
+ pub fn args<'a>(&'a self) -> impl Iterator<Item = DiagnosticArg<'a, 'static>> {
+ self.args.iter()
}
pub fn set_arg(
@@ -938,7 +898,7 @@ impl Diagnostic {
name: impl Into<Cow<'static, str>>,
arg: impl IntoDiagnosticArg,
) -> &mut Self {
- self.args.push((name.into(), arg.into_diagnostic_arg()));
+ self.args.insert(name.into(), arg.into_diagnostic_arg());
self
}
@@ -949,7 +909,7 @@ impl Diagnostic {
/// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by
/// combining it with the primary message of the diagnostic (if translatable, otherwise it just
/// passes the user's string along).
- fn subdiagnostic_message_to_diagnostic_message(
+ pub(crate) fn subdiagnostic_message_to_diagnostic_message(
&self,
attr: impl Into<SubdiagnosticMessage>,
) -> DiagnosticMessage {
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index 7e29dc207..9b41234dc 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -5,6 +5,7 @@ use crate::{
};
use crate::{Handler, Level, MultiSpan, StashKey};
use rustc_lint_defs::Applicability;
+use rustc_span::source_map::Spanned;
use rustc_span::Span;
use std::borrow::Cow;
@@ -13,6 +14,28 @@ use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::thread::panicking;
+/// Trait implemented by error types. This should not be implemented manually. Instead, use
+/// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic].
+#[cfg_attr(bootstrap, rustc_diagnostic_item = "SessionDiagnostic")]
+#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "IntoDiagnostic")]
+pub trait IntoDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> {
+ /// Write out as a diagnostic out of `Handler`.
+ #[must_use]
+ fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, T>;
+}
+
+impl<'a, T, E> IntoDiagnostic<'a, E> for Spanned<T>
+where
+ T: IntoDiagnostic<'a, E>,
+ E: EmissionGuarantee,
+{
+ fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, E> {
+ let mut diag = self.node.into_diagnostic(handler);
+ diag.set_span(self.span);
+ diag
+ }
+}
+
/// Used for emitting structured error messages and other diagnostic information.
///
/// If there is some state in a downstream crate you would like to
@@ -232,6 +255,56 @@ impl EmissionGuarantee for () {
}
}
+/// Marker type which enables implementation of `create_note` and `emit_note` functions for
+/// note-without-error struct diagnostics.
+#[derive(Copy, Clone)]
+pub struct Noted;
+
+impl<'a> DiagnosticBuilder<'a, Noted> {
+ /// Convenience function for internal use, clients should use one of the
+ /// `struct_*` methods on [`Handler`].
+ pub(crate) fn new_note(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
+ let diagnostic = Diagnostic::new_with_code(Level::Note, None, message);
+ Self::new_diagnostic_note(handler, diagnostic)
+ }
+
+ /// Creates a new `DiagnosticBuilder` with an already constructed
+ /// diagnostic.
+ pub(crate) fn new_diagnostic_note(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
+ debug!("Created new diagnostic");
+ Self {
+ inner: DiagnosticBuilderInner {
+ state: DiagnosticBuilderState::Emittable(handler),
+ diagnostic: Box::new(diagnostic),
+ },
+ _marker: PhantomData,
+ }
+ }
+}
+
+impl EmissionGuarantee for Noted {
+ fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
+ match db.inner.state {
+ // First `.emit()` call, the `&Handler` is still available.
+ DiagnosticBuilderState::Emittable(handler) => {
+ db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
+ handler.emit_diagnostic(&mut db.inner.diagnostic);
+ }
+ // `.emit()` was previously called, disallowed from repeating it.
+ DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
+ }
+
+ Noted
+ }
+
+ fn make_diagnostic_builder(
+ handler: &Handler,
+ msg: impl Into<DiagnosticMessage>,
+ ) -> DiagnosticBuilder<'_, Self> {
+ DiagnosticBuilder::new_note(handler, msg)
+ }
+}
+
impl<'a> DiagnosticBuilder<'a, !> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
@@ -570,7 +643,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
forward!(pub fn subdiagnostic(
&mut self,
- subdiagnostic: impl crate::AddSubdiagnostic
+ subdiagnostic: impl crate::AddToDiagnostic
) -> &mut Self);
}
@@ -619,27 +692,3 @@ macro_rules! struct_span_err {
macro_rules! error_code {
($code:ident) => {{ $crate::DiagnosticId::Error(stringify!($code).to_owned()) }};
}
-
-/// Wrapper around a `DiagnosticBuilder` for creating lints.
-pub struct LintDiagnosticBuilder<'a, G: EmissionGuarantee>(DiagnosticBuilder<'a, G>);
-
-impl<'a, G: EmissionGuarantee> LintDiagnosticBuilder<'a, G> {
- #[rustc_lint_diagnostics]
- /// Return the inner `DiagnosticBuilder`, first setting the primary message to `msg`.
- pub fn build(mut self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'a, G> {
- self.0.set_primary_message(msg);
- self.0.set_is_lint();
- self.0
- }
-
- /// Create a `LintDiagnosticBuilder` from some existing `DiagnosticBuilder`.
- pub fn new(err: DiagnosticBuilder<'a, G>) -> LintDiagnosticBuilder<'a, G> {
- LintDiagnosticBuilder(err)
- }
-}
-
-impl<'a> LintDiagnosticBuilder<'a, ErrorGuaranteed> {
- pub fn forget_guarantee(self) -> LintDiagnosticBuilder<'a, ()> {
- LintDiagnosticBuilder(self.0.forget_guarantee())
- }
-}
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
new file mode 100644
index 000000000..7640b2919
--- /dev/null
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -0,0 +1,222 @@
+use crate::{
+ fluent, DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg,
+};
+use rustc_ast as ast;
+use rustc_ast_pretty::pprust;
+use rustc_hir as hir;
+use rustc_lint_defs::Level;
+use rustc_span::edition::Edition;
+use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
+use rustc_target::abi::TargetDataLayoutErrors;
+use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
+use std::borrow::Cow;
+use std::fmt;
+use std::num::ParseIntError;
+use std::path::{Path, PathBuf};
+
+pub struct DiagnosticArgFromDisplay<'a>(pub &'a dyn fmt::Display);
+
+impl IntoDiagnosticArg for DiagnosticArgFromDisplay<'_> {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ self.0.to_string().into_diagnostic_arg()
+ }
+}
+
+impl<'a> From<&'a dyn fmt::Display> for DiagnosticArgFromDisplay<'a> {
+ fn from(t: &'a dyn fmt::Display) -> Self {
+ DiagnosticArgFromDisplay(t)
+ }
+}
+
+impl<'a, T: fmt::Display> From<&'a T> for DiagnosticArgFromDisplay<'a> {
+ fn from(t: &'a T) -> Self {
+ DiagnosticArgFromDisplay(t)
+ }
+}
+
+macro_rules! into_diagnostic_arg_using_display {
+ ($( $ty:ty ),+ $(,)?) => {
+ $(
+ impl IntoDiagnosticArg for $ty {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ self.to_string().into_diagnostic_arg()
+ }
+ }
+ )+
+ }
+}
+
+into_diagnostic_arg_using_display!(
+ i8,
+ u8,
+ i16,
+ u16,
+ i32,
+ u32,
+ i64,
+ u64,
+ i128,
+ u128,
+ std::io::Error,
+ std::num::NonZeroU32,
+ hir::Target,
+ Edition,
+ Ident,
+ MacroRulesNormalizedIdent,
+ ParseIntError,
+ StackProtector,
+ &TargetTriple,
+ SplitDebuginfo
+);
+
+impl IntoDiagnosticArg for bool {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ if self {
+ DiagnosticArgValue::Str(Cow::Borrowed("true"))
+ } else {
+ DiagnosticArgValue::Str(Cow::Borrowed("false"))
+ }
+ }
+}
+
+impl IntoDiagnosticArg for char {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self)))
+ }
+}
+
+impl IntoDiagnosticArg for Symbol {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ self.to_ident_string().into_diagnostic_arg()
+ }
+}
+
+impl<'a> IntoDiagnosticArg for &'a str {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ self.to_string().into_diagnostic_arg()
+ }
+}
+
+impl IntoDiagnosticArg for String {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::Owned(self))
+ }
+}
+
+impl<'a> IntoDiagnosticArg for &'a Path {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::Owned(self.display().to_string()))
+ }
+}
+
+impl IntoDiagnosticArg for PathBuf {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::Owned(self.display().to_string()))
+ }
+}
+
+impl IntoDiagnosticArg for usize {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Number(self)
+ }
+}
+
+impl IntoDiagnosticArg for PanicStrategy {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::Owned(self.desc().to_string()))
+ }
+}
+
+impl IntoDiagnosticArg for hir::ConstContext {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::Borrowed(match self {
+ hir::ConstContext::ConstFn => "constant function",
+ hir::ConstContext::Static(_) => "static",
+ hir::ConstContext::Const => "constant",
+ }))
+ }
+}
+
+impl IntoDiagnosticArg for ast::Path {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::Owned(pprust::path_to_string(&self)))
+ }
+}
+
+impl IntoDiagnosticArg for ast::token::Token {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(pprust::token_to_string(&self))
+ }
+}
+
+impl IntoDiagnosticArg for ast::token::TokenKind {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(pprust::token_kind_to_string(&self))
+ }
+}
+
+impl IntoDiagnosticArg for Level {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::Borrowed(match self {
+ Level::Allow => "-A",
+ Level::Warn => "-W",
+ Level::ForceWarn(_) => "--force-warn",
+ Level::Deny => "-D",
+ Level::Forbid => "-F",
+ Level::Expect(_) => {
+ unreachable!("lints with the level of `expect` should not run this code");
+ }
+ }))
+ }
+}
+
+impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> {
+ fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
+ let mut diag;
+ match self {
+ TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => {
+ diag = handler.struct_fatal(fluent::errors_target_invalid_address_space);
+ diag.set_arg("addr_space", addr_space);
+ diag.set_arg("cause", cause);
+ diag.set_arg("err", err);
+ diag
+ }
+ TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => {
+ diag = handler.struct_fatal(fluent::errors_target_invalid_bits);
+ diag.set_arg("kind", kind);
+ diag.set_arg("bit", bit);
+ diag.set_arg("cause", cause);
+ diag.set_arg("err", err);
+ diag
+ }
+ TargetDataLayoutErrors::MissingAlignment { cause } => {
+ diag = handler.struct_fatal(fluent::errors_target_missing_alignment);
+ diag.set_arg("cause", cause);
+ diag
+ }
+ TargetDataLayoutErrors::InvalidAlignment { cause, err } => {
+ diag = handler.struct_fatal(fluent::errors_target_invalid_alignment);
+ diag.set_arg("cause", cause);
+ diag.set_arg("err", err);
+ diag
+ }
+ TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => {
+ diag = handler.struct_fatal(fluent::errors_target_inconsistent_architecture);
+ diag.set_arg("dl", dl);
+ diag.set_arg("target", target);
+ diag
+ }
+ TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => {
+ diag = handler.struct_fatal(fluent::errors_target_inconsistent_pointer_width);
+ diag.set_arg("pointer_size", pointer_size);
+ diag.set_arg("target", target);
+ diag
+ }
+ TargetDataLayoutErrors::InvalidBitsSize { err } => {
+ diag = handler.struct_fatal(fluent::errors_target_invalid_bits_size);
+ diag.set_arg("err", err);
+ diag
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 66fbb8f12..cd6413bc3 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -14,7 +14,7 @@ use rustc_span::{FileLines, SourceFile, Span};
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
use crate::styled_buffer::StyledBuffer;
-use crate::translation::Translate;
+use crate::translation::{to_fluent_args, Translate};
use crate::{
CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, FluentBundle, Handler,
LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle,
@@ -535,7 +535,7 @@ impl Emitter for EmitterWriter {
}
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
- let fluent_args = self.to_fluent_args(diag.args());
+ let fluent_args = to_fluent_args(diag.args());
let mut children = diag.children.clone();
let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args);
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 1680c6acc..4cc7be47f 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -13,7 +13,7 @@ use rustc_span::source_map::{FilePathMapping, SourceMap};
use crate::emitter::{Emitter, HumanReadableErrorType};
use crate::registry::Registry;
-use crate::translation::Translate;
+use crate::translation::{to_fluent_args, Translate};
use crate::DiagnosticId;
use crate::{
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
@@ -312,7 +312,7 @@ struct UnusedExterns<'a, 'b, 'c> {
impl Diagnostic {
fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic {
- let args = je.to_fluent_args(diag.args());
+ let args = to_fluent_args(diag.args());
let sugg = diag.suggestions.iter().flatten().map(|sugg| {
let translated_message = je.translate_message(&sugg.msg, &args);
Diagnostic {
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index a7b01feeb..0963ea71f 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -7,7 +7,6 @@
#![feature(if_let_guard)]
#![feature(adt_const_params)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(never_type)]
#![feature(result_option_inspect)]
#![feature(rustc_attrs)]
@@ -31,7 +30,7 @@ use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::{self, Lock, Lrc};
use rustc_data_structures::AtomicRef;
pub use rustc_error_messages::{
- fallback_fluent_bundle, fluent, fluent_bundle, DiagnosticMessage, FluentBundle,
+ fallback_fluent_bundle, fluent, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle,
LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage,
DEFAULT_LOCALE_RESOURCES,
};
@@ -52,6 +51,7 @@ use termcolor::{Color, ColorSpec};
pub mod annotate_snippet_emitter_writer;
mod diagnostic;
mod diagnostic_builder;
+mod diagnostic_impls;
pub mod emitter;
pub mod json;
mod lock;
@@ -60,15 +60,17 @@ mod snippet;
mod styled_buffer;
pub mod translation;
+pub use diagnostic_builder::IntoDiagnostic;
pub use snippet::Style;
-pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a, ErrorGuaranteed>>;
+pub type PErr<'a> = DiagnosticBuilder<'a, ErrorGuaranteed>;
+pub type PResult<'a, T> = Result<T, PErr<'a>>;
// `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
-// (See also the comment on `DiagnosticBuilder`'s `diagnostic` field.)
+// (See also the comment on `DiagnosticBuilderInner`'s `diagnostic` field.)
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16);
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64", not(bootstrap)))]
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
@@ -370,10 +372,11 @@ impl fmt::Display for ExplicitBug {
impl error::Error for ExplicitBug {}
pub use diagnostic::{
- AddSubdiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay,
- DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
+ AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId,
+ DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
};
-pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, LintDiagnosticBuilder};
+pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted};
+pub use diagnostic_impls::DiagnosticArgFromDisplay;
use std::backtrace::Backtrace;
/// A handler deals with errors and other compiler output.
@@ -410,7 +413,7 @@ struct HandlerInner {
/// would be unnecessary repetition.
taught_diagnostics: FxHashSet<DiagnosticId>,
- /// Used to suggest rustc --explain <error code>
+ /// Used to suggest rustc --explain `<error code>`
emitted_diagnostic_codes: FxIndexSet<DiagnosticId>,
/// This set contains a hash of every diagnostic that has been emitted by
@@ -436,11 +439,11 @@ struct HandlerInner {
/// have been converted.
check_unstable_expect_diagnostics: bool,
- /// Expected [`Diagnostic`]s store a [`LintExpectationId`] as part of
+ /// Expected [`Diagnostic`][diagnostic::Diagnostic]s store a [`LintExpectationId`] as part of
/// the lint level. [`LintExpectationId`]s created early during the compilation
/// (before `HirId`s have been defined) are not stable and can therefore not be
/// stored on disk. This buffer stores these diagnostics until the ID has been
- /// replaced by a stable [`LintExpectationId`]. The [`Diagnostic`]s are the
+ /// replaced by a stable [`LintExpectationId`]. The [`Diagnostic`][diagnostic::Diagnostic]s are the
/// submitted for storage and added to the list of fulfilled expectations.
unstable_expect_diagnostics: Vec<Diagnostic>,
@@ -459,6 +462,10 @@ pub enum StashKey {
ItemNoType,
UnderscoreForArrayLengths,
EarlySyntaxWarning,
+ CallIntoMethod,
+ /// When an invalid lifetime e.g. `'2` should be reinterpreted
+ /// as a char literal in the parser
+ LifetimeIsChar,
}
fn default_track_diagnostic(_: &Diagnostic) {}
@@ -596,6 +603,17 @@ impl Handler {
}
}
+ /// Translate `message` eagerly with `args`.
+ pub fn eagerly_translate<'a>(
+ &self,
+ message: DiagnosticMessage,
+ args: impl Iterator<Item = DiagnosticArg<'a, 'static>>,
+ ) -> SubdiagnosticMessage {
+ let inner = self.inner.borrow();
+ let args = crate::translation::to_fluent_args(args);
+ SubdiagnosticMessage::Eager(inner.emitter.translate_message(&message, &args).to_string())
+ }
+
// This is here to not allow mutation of flags;
// as of this writing it's only used in tests in librustc_middle.
pub fn can_emit_warnings(&self) -> bool {
@@ -1028,6 +1046,39 @@ impl Handler {
self.inner.borrow_mut().emit_diagnostic(diagnostic)
}
+ pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
+ self.create_err(err).emit()
+ }
+
+ pub fn create_err<'a>(
+ &'a self,
+ err: impl IntoDiagnostic<'a>,
+ ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+ err.into_diagnostic(self)
+ }
+
+ pub fn create_warning<'a>(
+ &'a self,
+ warning: impl IntoDiagnostic<'a, ()>,
+ ) -> DiagnosticBuilder<'a, ()> {
+ warning.into_diagnostic(self)
+ }
+
+ pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
+ self.create_warning(warning).emit()
+ }
+
+ pub fn create_fatal<'a>(
+ &'a self,
+ fatal: impl IntoDiagnostic<'a, !>,
+ ) -> DiagnosticBuilder<'a, !> {
+ fatal.into_diagnostic(self)
+ }
+
+ pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! {
+ self.create_fatal(fatal).emit()
+ }
+
fn emit_diag_at_span(
&self,
mut diag: Diagnostic,
@@ -1100,6 +1151,12 @@ impl Handler {
);
std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
}
+
+ pub fn flush_delayed(&self) {
+ let mut inner = self.inner.lock();
+ let bugs = std::mem::replace(&mut inner.delayed_span_bugs, Vec::new());
+ inner.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued");
+ }
}
impl HandlerInner {
@@ -1171,7 +1228,7 @@ impl HandlerInner {
if let Some(expectation_id) = diagnostic.level.get_expectation_id() {
self.suppressed_expected_diag = true;
- self.fulfilled_expectations.insert(expectation_id);
+ self.fulfilled_expectations.insert(expectation_id.normalize());
}
if matches!(diagnostic.level, Warning(_))
diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs
index 4f407badb..a7737b467 100644
--- a/compiler/rustc_errors/src/translation.rs
+++ b/compiler/rustc_errors/src/translation.rs
@@ -4,6 +4,27 @@ use rustc_data_structures::sync::Lrc;
use rustc_error_messages::FluentArgs;
use std::borrow::Cow;
+/// Convert diagnostic arguments (a rustc internal type that exists to implement
+/// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
+///
+/// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then
+/// passed around as a reference thereafter.
+pub fn to_fluent_args<'iter, 'arg: 'iter>(
+ iter: impl Iterator<Item = DiagnosticArg<'iter, 'arg>>,
+) -> FluentArgs<'arg> {
+ let mut args = if let Some(size) = iter.size_hint().1 {
+ FluentArgs::with_capacity(size)
+ } else {
+ FluentArgs::new()
+ };
+
+ for (k, v) in iter {
+ args.set(k.clone(), v.clone());
+ }
+
+ args
+}
+
pub trait Translate {
/// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no
/// language was requested by the user then this will be `None` and `fallback_fluent_bundle`
@@ -15,15 +36,6 @@ pub trait Translate {
/// unavailable for the requested locale.
fn fallback_fluent_bundle(&self) -> &FluentBundle;
- /// Convert diagnostic arguments (a rustc internal type that exists to implement
- /// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation.
- ///
- /// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then
- /// passed around as a reference thereafter.
- fn to_fluent_args<'arg>(&self, args: &[DiagnosticArg<'arg>]) -> FluentArgs<'arg> {
- FromIterator::from_iter(args.iter().cloned())
- }
-
/// Convert `DiagnosticMessage`s to a string, performing translation if necessary.
fn translate_messages(
&self,
@@ -43,7 +55,9 @@ pub trait Translate {
) -> Cow<'_, str> {
trace!(?message, ?args);
let (identifier, attr) = match message {
- DiagnosticMessage::Str(msg) => return Cow::Borrowed(&msg),
+ DiagnosticMessage::Str(msg) | DiagnosticMessage::Eager(msg) => {
+ return Cow::Borrowed(&msg);
+ }
DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
};
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index e1da3ecde..c8de60ccb 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -10,17 +10,19 @@ use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind
use rustc_attr::{self as attr, Deprecation, Stability};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_data_structures::sync::{self, Lrc};
-use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, PResult};
+use rustc_errors::{
+ Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan, PResult,
+};
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics};
use rustc_parse::{self, parser, MACRO_ARGUMENTS};
-use rustc_session::{parse::ParseSess, Limit, Session, SessionDiagnostic};
+use rustc_session::{parse::ParseSess, Limit, Session};
use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
use rustc_span::edition::Edition;
use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{FileName, Span, DUMMY_SP};
+use rustc_span::{BytePos, FileName, RealFileName, Span, DUMMY_SP};
use smallvec::{smallvec, SmallVec};
use std::default::Default;
@@ -1109,12 +1111,12 @@ impl<'a> ExtCtxt<'a> {
pub fn create_err(
&self,
- err: impl SessionDiagnostic<'a>,
+ err: impl IntoDiagnostic<'a>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
self.sess.create_err(err)
}
- pub fn emit_err(&self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed {
+ pub fn emit_err(&self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
self.sess.emit_err(err)
}
@@ -1226,8 +1228,9 @@ pub fn expr_to_spanned_string<'a>(
ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)),
ast::LitKind::ByteStr(_) => {
let mut err = cx.struct_span_err(l.span, err_msg);
+ let span = expr.span.shrink_to_lo();
err.span_suggestion(
- expr.span.shrink_to_lo(),
+ span.with_hi(span.lo() + BytePos(1)),
"consider removing the leading `b`",
"",
Applicability::MaybeIncorrect,
@@ -1420,16 +1423,40 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &ParseSess) -> bool {
if let ast::ItemKind::Enum(enum_def, _) = &item.kind {
if let [variant] = &*enum_def.variants {
if variant.ident.name == sym::Input {
- sess.buffer_lint_with_diagnostic(
- &PROC_MACRO_BACK_COMPAT,
- item.ident.span,
- ast::CRATE_NODE_ID,
- "using `procedural-masquerade` crate",
- BuiltinLintDiagnostics::ProcMacroBackCompat(
- "The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. \
- Versions of this crate below 0.1.7 will eventually stop compiling.".to_string())
- );
- return true;
+ let filename = sess.source_map().span_to_filename(item.ident.span);
+ if let FileName::Real(RealFileName::LocalPath(path)) = filename {
+ if let Some(c) = path
+ .components()
+ .flat_map(|c| c.as_os_str().to_str())
+ .find(|c| c.starts_with("rental") || c.starts_with("allsorts-rental"))
+ {
+ let crate_matches = if c.starts_with("allsorts-rental") {
+ true
+ } else {
+ let mut version = c.trim_start_matches("rental-").split(".");
+ version.next() == Some("0")
+ && version.next() == Some("5")
+ && version
+ .next()
+ .and_then(|c| c.parse::<u32>().ok())
+ .map_or(false, |v| v < 6)
+ };
+
+ if crate_matches {
+ sess.buffer_lint_with_diagnostic(
+ &PROC_MACRO_BACK_COMPAT,
+ item.ident.span,
+ ast::CRATE_NODE_ID,
+ "using an old version of `rental`",
+ BuiltinLintDiagnostics::ProcMacroBackCompat(
+ "older versions of the `rental` crate will stop compiling in future versions of Rust; \
+ please update to `rental` v0.5.6, or switch to one of the `rental` alternatives".to_string()
+ )
+ );
+ return true;
+ }
+ }
+ }
}
}
}
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 50d2be3ce..0952e65cf 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -252,6 +252,10 @@ impl<'a> ExtCtxt<'a> {
self.expr_ident(span, Ident::with_dummy_span(kw::SelfLower))
}
+ pub fn expr_field(&self, span: Span, expr: P<Expr>, field: Ident) -> P<ast::Expr> {
+ self.expr(span, ast::ExprKind::Field(expr, field))
+ }
+
pub fn expr_binary(
&self,
sp: Span,
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 8d4e36407..1d2b1298a 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -469,6 +469,7 @@ impl<'a> StripUnconfigured<'a> {
}
/// If attributes are not allowed on expressions, emit an error for `attr`
+ #[instrument(level = "trace", skip(self))]
pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
if !self.features.map_or(true, |features| features.stmt_expr_attributes) {
let mut err = feature_err(
@@ -486,9 +487,12 @@ impl<'a> StripUnconfigured<'a> {
}
}
- pub fn configure_expr(&self, expr: &mut P<ast::Expr>) {
- for attr in expr.attrs.iter() {
- self.maybe_emit_expr_attr_err(attr);
+ #[instrument(level = "trace", skip(self))]
+ pub fn configure_expr(&self, expr: &mut P<ast::Expr>, method_receiver: bool) {
+ if !method_receiver {
+ for attr in expr.attrs.iter() {
+ self.maybe_emit_expr_attr_err(attr);
+ }
}
// If an expr is valid to cfg away it will have been removed by the
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 0feae0deb..d383f4832 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -1,46 +1,46 @@
-use rustc_macros::SessionDiagnostic;
+use rustc_macros::Diagnostic;
use rustc_span::symbol::MacroRulesNormalizedIdent;
use rustc_span::Span;
-#[derive(SessionDiagnostic)]
-#[diag(expand::expr_repeat_no_syntax_vars)]
+#[derive(Diagnostic)]
+#[diag(expand_expr_repeat_no_syntax_vars)]
pub(crate) struct NoSyntaxVarsExprRepeat {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(expand::must_repeat_once)]
+#[derive(Diagnostic)]
+#[diag(expand_must_repeat_once)]
pub(crate) struct MustRepeatOnce {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(expand::count_repetition_misplaced)]
+#[derive(Diagnostic)]
+#[diag(expand_count_repetition_misplaced)]
pub(crate) struct CountRepetitionMisplaced {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(expand::meta_var_expr_unrecognized_var)]
+#[derive(Diagnostic)]
+#[diag(expand_meta_var_expr_unrecognized_var)]
pub(crate) struct MetaVarExprUnrecognizedVar {
#[primary_span]
pub span: Span,
pub key: MacroRulesNormalizedIdent,
}
-#[derive(SessionDiagnostic)]
-#[diag(expand::var_still_repeating)]
+#[derive(Diagnostic)]
+#[diag(expand_var_still_repeating)]
pub(crate) struct VarStillRepeating {
#[primary_span]
pub span: Span,
pub ident: MacroRulesNormalizedIdent,
}
-#[derive(SessionDiagnostic)]
-#[diag(expand::meta_var_dif_seq_matchers)]
+#[derive(Diagnostic)]
+#[diag(expand_meta_var_dif_seq_matchers)]
pub(crate) struct MetaVarsDifSeqMatchers {
#[primary_span]
pub span: Span,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index c2add852a..57713fb3c 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -50,6 +50,7 @@ macro_rules! ast_fragments {
/// Can also serve as an input and intermediate result for macro expansion operations.
pub enum AstFragment {
OptExpr(Option<P<ast::Expr>>),
+ MethodReceiverExpr(P<ast::Expr>),
$($Kind($AstTy),)*
}
@@ -57,6 +58,7 @@ macro_rules! ast_fragments {
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum AstFragmentKind {
OptExpr,
+ MethodReceiverExpr,
$($Kind,)*
}
@@ -64,6 +66,7 @@ macro_rules! ast_fragments {
pub fn name(self) -> &'static str {
match self {
AstFragmentKind::OptExpr => "expression",
+ AstFragmentKind::MethodReceiverExpr => "expression",
$(AstFragmentKind::$Kind => $kind_name,)*
}
}
@@ -72,6 +75,8 @@ macro_rules! ast_fragments {
match self {
AstFragmentKind::OptExpr =>
result.make_expr().map(Some).map(AstFragment::OptExpr),
+ AstFragmentKind::MethodReceiverExpr =>
+ result.make_expr().map(AstFragment::MethodReceiverExpr),
$(AstFragmentKind::$Kind => result.$make_ast().map(AstFragment::$Kind),)*
}
}
@@ -98,6 +103,13 @@ macro_rules! ast_fragments {
}
}
+ pub fn make_method_receiver_expr(self) -> P<ast::Expr> {
+ match self {
+ AstFragment::MethodReceiverExpr(expr) => expr,
+ _ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
+ }
+ }
+
$(pub fn $make_ast(self) -> $AstTy {
match self {
AstFragment::$Kind(ast) => ast,
@@ -120,6 +132,7 @@ macro_rules! ast_fragments {
}
});
}
+ AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr),
$($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)*
$($(AstFragment::$Kind(ast) =>
ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)?)*
@@ -130,6 +143,7 @@ macro_rules! ast_fragments {
match *self {
AstFragment::OptExpr(Some(ref expr)) => visitor.visit_expr(expr),
AstFragment::OptExpr(None) => {}
+ AstFragment::MethodReceiverExpr(ref expr) => visitor.visit_method_receiver_expr(expr),
$($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)*
$($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] {
visitor.$visit_ast_elt(ast_elt, $($args)*);
@@ -222,6 +236,7 @@ impl AstFragmentKind {
match self {
AstFragmentKind::OptExpr
| AstFragmentKind::Expr
+ | AstFragmentKind::MethodReceiverExpr
| AstFragmentKind::Stmts
| AstFragmentKind::Ty
| AstFragmentKind::Pat => SupportsMacroExpansion::Yes { supports_inner_attrs: false },
@@ -285,6 +300,9 @@ impl AstFragmentKind {
AstFragmentKind::Expr => AstFragment::Expr(
items.next().expect("expected exactly one expression").expect_expr(),
),
+ AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(
+ items.next().expect("expected exactly one expression").expect_expr(),
+ ),
AstFragmentKind::OptExpr => {
AstFragment::OptExpr(items.next().map(Annotatable::expect_expr))
}
@@ -327,7 +345,7 @@ impl InvocationKind {
fn placeholder_visibility(&self) -> Option<ast::Visibility> {
// HACK: For unnamed fields placeholders should have the same visibility as the actual
// fields because for tuple structs/variants resolve determines visibilities of their
- // constructor using these field visibilities before attributes on them are are expanded.
+ // constructor using these field visibilities before attributes on them are expanded.
// The assumption is that the attribute expansion cannot change field visibilities,
// and it holds because only inert attributes are supported in this position.
match self {
@@ -893,6 +911,7 @@ pub fn parse_ast_fragment<'a>(
AstFragment::Stmts(stmts)
}
AstFragmentKind::Expr => AstFragment::Expr(this.parse_expr()?),
+ AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(this.parse_expr()?),
AstFragmentKind::OptExpr => {
if this.token != token::Eof {
AstFragment::OptExpr(Some(this.parse_expr()?))
@@ -937,13 +956,12 @@ pub fn ensure_complete_parse<'a>(
kind_name,
);
err.note(&msg);
- let semi_span = this.sess.source_map().next_point(span);
- let semi_full_span = semi_span.to(this.sess.source_map().next_point(semi_span));
- match this.sess.source_map().span_to_snippet(semi_full_span) {
+ let semi_span = this.sess.source_map().next_point(span);
+ match this.sess.source_map().span_to_snippet(semi_span) {
Ok(ref snippet) if &snippet[..] != ";" && kind_name == "expression" => {
err.span_suggestion(
- semi_span,
+ span.shrink_to_hi(),
"you might be missing a semicolon here",
";",
Applicability::MaybeIncorrect,
@@ -1478,6 +1496,42 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, OptExprTag> {
}
}
+/// This struct is a hack to workaround unstable of `stmt_expr_attributes`.
+/// It can be removed once that feature is stabilized.
+struct MethodReceiverTag;
+impl DummyAstNode for MethodReceiverTag {
+ fn dummy() -> MethodReceiverTag {
+ MethodReceiverTag
+ }
+}
+impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, MethodReceiverTag> {
+ type OutputTy = Self;
+ type AttrsTy = ast::AttrVec;
+ const KIND: AstFragmentKind = AstFragmentKind::MethodReceiverExpr;
+ fn descr() -> &'static str {
+ "an expression"
+ }
+ fn to_annotatable(self) -> Annotatable {
+ Annotatable::Expr(self.wrapped)
+ }
+ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+ AstNodeWrapper::new(fragment.make_method_receiver_expr(), MethodReceiverTag)
+ }
+ fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
+ noop_visit_expr(&mut self.wrapped, visitor)
+ }
+ fn is_mac_call(&self) -> bool {
+ matches!(self.wrapped.kind, ast::ExprKind::MacCall(..))
+ }
+ fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
+ let node = self.wrapped.into_inner();
+ match node.kind {
+ ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+ _ => unreachable!(),
+ }
+ }
+}
+
struct InvocationCollector<'a, 'b> {
cx: &'a mut ExtCtxt<'b>,
invocations: Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>,
@@ -1841,6 +1895,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
self.visit_node(node)
}
+ fn visit_method_receiver_expr(&mut self, node: &mut P<ast::Expr>) {
+ visit_clobber(node, |node| {
+ let mut wrapper = AstNodeWrapper::new(node, MethodReceiverTag);
+ self.visit_node(&mut wrapper);
+ wrapper.wrapped
+ })
+ }
+
fn filter_map_expr(&mut self, node: P<ast::Expr>) -> Option<P<ast::Expr>> {
self.flat_map_node(AstNodeWrapper::new(node, OptExprTag))
}
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index ffc9abe64..b34de94fb 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -3,7 +3,6 @@
#![feature(associated_type_defaults)]
#![feature(if_let_guard)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(macro_metavar_expr)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_internals)]
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 7764ffd24..f6fe38174 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -14,7 +14,7 @@ use rustc_ast::{NodeId, DUMMY_NODE_ID};
use rustc_ast_pretty::pprust;
use rustc_attr::{self as attr, TransparencyError};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage};
use rustc_feature::Features;
use rustc_lint_defs::builtin::{
RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
@@ -68,19 +68,22 @@ fn emit_frag_parse_err(
kind: AstFragmentKind,
) {
// FIXME(davidtwco): avoid depending on the error message text
- if parser.token == token::Eof && e.message[0].0.expect_str().ends_with(", found `<eof>`") {
- if !e.span.is_dummy() {
- // early end of macro arm (#52866)
- e.replace_span_with(parser.sess.source_map().next_point(parser.token.span));
- }
+ if parser.token == token::Eof
+ && let DiagnosticMessage::Str(message) = &e.message[0].0
+ && message.ends_with(", found `<eof>`")
+ {
let msg = &e.message[0];
e.message[0] = (
- rustc_errors::DiagnosticMessage::Str(format!(
+ DiagnosticMessage::Str(format!(
"macro expansion ends with an incomplete expression: {}",
- msg.0.expect_str().replace(", found `<eof>`", ""),
+ message.replace(", found `<eof>`", ""),
)),
msg.1,
);
+ if !e.span.is_dummy() {
+ // early end of macro arm (#52866)
+ e.replace_span_with(parser.token.span.shrink_to_hi());
+ }
}
if e.span.is_dummy() {
// Get around lack of span in error (#30128)
@@ -247,6 +250,7 @@ fn expand_macro<'cx>(
// hacky, but speeds up the `html5ever` benchmark significantly. (Issue
// 68836 suggests a more comprehensive but more complex change to deal with
// this situation.)
+ // FIXME(Nilstrieb): Stop recovery from happening on this parser and retry later with recovery if the macro failed to match.
let parser = parser_from_cx(sess, arg.clone());
// Try each arm's matchers.
@@ -593,14 +597,14 @@ pub fn compile_declarative_macro(
(mk_syn_ext(expander), rule_spans)
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
enum ExplainDocComment {
- #[label(expand::explain_doc_comment_inner)]
+ #[label(expand_explain_doc_comment_inner)]
Inner {
#[primary_span]
span: Span,
},
- #[label(expand::explain_doc_comment_outer)]
+ #[label(expand_explain_doc_comment_outer)]
Outer {
#[primary_span]
span: Span,
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 3b0d5ddb9..faaf3b3fe 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -55,6 +55,7 @@ pub fn placeholder(
}),
AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()),
AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())),
+ AstFragmentKind::MethodReceiverExpr => AstFragment::MethodReceiverExpr(expr_placeholder()),
AstFragmentKind::Items => AstFragment::Items(smallvec![P(ast::Item {
id,
span,
@@ -296,6 +297,13 @@ impl MutVisitor for PlaceholderExpander {
}
}
+ fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) {
+ match expr.kind {
+ ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_method_receiver_expr(),
+ _ => noop_visit_expr(expr, self),
+ }
+ }
+
fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
match expr.kind {
ast::ExprKind::MacCall(_) => self.remove(expr.id).make_opt_expr(),
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 59a7b668a..cc2858d3f 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -1,5 +1,8 @@
use crate::base::ExtCtxt;
-
+use pm::bridge::{
+ server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree,
+};
+use pm::{Delimiter, Level, LineColumn};
use rustc_ast as ast;
use rustc_ast::token;
use rustc_ast::tokenstream::{self, Spacing::*, TokenStream};
@@ -13,11 +16,7 @@ use rustc_session::parse::ParseSess;
use rustc_span::def_id::CrateNum;
use rustc_span::symbol::{self, sym, Symbol};
use rustc_span::{BytePos, FileName, Pos, SourceFile, Span};
-
-use pm::bridge::{
- server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree,
-};
-use pm::{Delimiter, Level, LineColumn};
+use smallvec::{smallvec, SmallVec};
use std::ops::Bound;
trait FromInternal<T> {
@@ -110,10 +109,26 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
tokenstream::TokenTree::Token(token, spacing) => (token, spacing == Joint),
};
+ // Split the operator into one or more `Punct`s, one per character.
+ // The final one inherits the jointness of the original token. Any
+ // before that get `joint = true`.
let mut op = |s: &str| {
assert!(s.is_ascii());
- trees.extend(s.as_bytes().iter().enumerate().map(|(idx, &ch)| {
- TokenTree::Punct(Punct { ch, joint: joint || idx != s.len() - 1, span })
+ trees.extend(s.bytes().enumerate().map(|(i, ch)| {
+ let is_final = i == s.len() - 1;
+ // Split the token span into single chars. Unless the span
+ // is an unusual one, e.g. due to proc macro expansion. We
+ // determine this by assuming any span with a length that
+ // matches the operator length is a normal one, and any
+ // span with a different length is an unusual one.
+ let span = if (span.hi() - span.lo()).to_usize() == s.len() {
+ let lo = span.lo() + BytePos::from_usize(i);
+ let hi = lo + BytePos::from_usize(1);
+ span.with_lo(lo).with_hi(hi)
+ } else {
+ span
+ };
+ TokenTree::Punct(Punct { ch, joint: if is_final { joint } else { true }, span })
}));
};
@@ -237,23 +252,57 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
}
}
-impl ToInternal<TokenStream> for (TokenTree<TokenStream, Span, Symbol>, &mut Rustc<'_, '_>) {
- fn to_internal(self) -> TokenStream {
+// We use a `SmallVec` because the output size is always one or two `TokenTree`s.
+impl ToInternal<SmallVec<[tokenstream::TokenTree; 2]>>
+ for (TokenTree<TokenStream, Span, Symbol>, &mut Rustc<'_, '_>)
+{
+ fn to_internal(self) -> SmallVec<[tokenstream::TokenTree; 2]> {
use rustc_ast::token::*;
let (tree, rustc) = self;
- let (ch, joint, span) = match tree {
- TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span),
+ match tree {
+ TokenTree::Punct(Punct { ch, joint, span }) => {
+ let kind = match ch {
+ b'=' => Eq,
+ b'<' => Lt,
+ b'>' => Gt,
+ b'!' => Not,
+ b'~' => Tilde,
+ b'+' => BinOp(Plus),
+ b'-' => BinOp(Minus),
+ b'*' => BinOp(Star),
+ b'/' => BinOp(Slash),
+ b'%' => BinOp(Percent),
+ b'^' => BinOp(Caret),
+ b'&' => BinOp(And),
+ b'|' => BinOp(Or),
+ b'@' => At,
+ b'.' => Dot,
+ b',' => Comma,
+ b';' => Semi,
+ b':' => Colon,
+ b'#' => Pound,
+ b'$' => Dollar,
+ b'?' => Question,
+ b'\'' => SingleQuote,
+ _ => unreachable!(),
+ };
+ smallvec![if joint {
+ tokenstream::TokenTree::token_joint(kind, span)
+ } else {
+ tokenstream::TokenTree::token_alone(kind, span)
+ }]
+ }
TokenTree::Group(Group { delimiter, stream, span: DelimSpan { open, close, .. } }) => {
- return tokenstream::TokenStream::delimited(
+ smallvec![tokenstream::TokenTree::Delimited(
tokenstream::DelimSpan { open, close },
delimiter.to_internal(),
stream.unwrap_or_default(),
- );
+ )]
}
TokenTree::Ident(self::Ident { sym, is_raw, span }) => {
rustc.sess().symbol_gallery.insert(sym, span);
- return tokenstream::TokenStream::token_alone(Ident(sym, is_raw), span);
+ smallvec![tokenstream::TokenTree::token_alone(Ident(sym, is_raw), span)]
}
TokenTree::Literal(self::Literal {
kind: self::LitKind::Integer,
@@ -266,7 +315,7 @@ impl ToInternal<TokenStream> for (TokenTree<TokenStream, Span, Symbol>, &mut Rus
let integer = TokenKind::lit(token::Integer, symbol, suffix);
let a = tokenstream::TokenTree::token_alone(minus, span);
let b = tokenstream::TokenTree::token_alone(integer, span);
- return [a, b].into_iter().collect();
+ smallvec![a, b]
}
TokenTree::Literal(self::Literal {
kind: self::LitKind::Float,
@@ -279,46 +328,14 @@ impl ToInternal<TokenStream> for (TokenTree<TokenStream, Span, Symbol>, &mut Rus
let float = TokenKind::lit(token::Float, symbol, suffix);
let a = tokenstream::TokenTree::token_alone(minus, span);
let b = tokenstream::TokenTree::token_alone(float, span);
- return [a, b].into_iter().collect();
+ smallvec![a, b]
}
TokenTree::Literal(self::Literal { kind, symbol, suffix, span }) => {
- return tokenstream::TokenStream::token_alone(
+ smallvec![tokenstream::TokenTree::token_alone(
TokenKind::lit(kind.to_internal(), symbol, suffix),
span,
- );
+ )]
}
- };
-
- let kind = match ch {
- b'=' => Eq,
- b'<' => Lt,
- b'>' => Gt,
- b'!' => Not,
- b'~' => Tilde,
- b'+' => BinOp(Plus),
- b'-' => BinOp(Minus),
- b'*' => BinOp(Star),
- b'/' => BinOp(Slash),
- b'%' => BinOp(Percent),
- b'^' => BinOp(Caret),
- b'&' => BinOp(And),
- b'|' => BinOp(Or),
- b'@' => At,
- b'.' => Dot,
- b',' => Comma,
- b';' => Semi,
- b':' => Colon,
- b'#' => Pound,
- b'$' => Dollar,
- b'?' => Question,
- b'\'' => SingleQuote,
- _ => unreachable!(),
- };
-
- if joint {
- tokenstream::TokenStream::token_joint(kind, span)
- } else {
- tokenstream::TokenStream::token_alone(kind, span)
}
}
}
@@ -533,7 +550,7 @@ impl server::TokenStream for Rustc<'_, '_> {
&mut self,
tree: TokenTree<Self::TokenStream, Self::Span, Self::Symbol>,
) -> Self::TokenStream {
- (tree, &mut *self).to_internal()
+ Self::TokenStream::new((tree, &mut *self).to_internal().into_iter().collect::<Vec<_>>())
}
fn concat_trees(
@@ -541,14 +558,14 @@ impl server::TokenStream for Rustc<'_, '_> {
base: Option<Self::TokenStream>,
trees: Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>>,
) -> Self::TokenStream {
- let mut builder = tokenstream::TokenStreamBuilder::new();
- if let Some(base) = base {
- builder.push(base);
- }
+ let mut stream =
+ if let Some(base) = base { base } else { tokenstream::TokenStream::default() };
for tree in trees {
- builder.push((tree, &mut *self).to_internal());
+ for tt in (tree, &mut *self).to_internal() {
+ stream.push_tree(tt);
+ }
}
- builder.build()
+ stream
}
fn concat_streams(
@@ -556,14 +573,12 @@ impl server::TokenStream for Rustc<'_, '_> {
base: Option<Self::TokenStream>,
streams: Vec<Self::TokenStream>,
) -> Self::TokenStream {
- let mut builder = tokenstream::TokenStreamBuilder::new();
- if let Some(base) = base {
- builder.push(base);
+ let mut stream =
+ if let Some(base) = base { base } else { tokenstream::TokenStream::default() };
+ for s in streams {
+ stream.push_stream(s);
}
- for stream in streams {
- builder.push(stream);
- }
- builder.build()
+ stream
}
fn into_trees(
@@ -689,6 +704,7 @@ impl server::Span for Rustc<'_, '_> {
fn source_text(&mut self, span: Self::Span) -> Option<String> {
self.sess().source_map().span_to_snippet(span).ok()
}
+
/// Saves the provided span into the metadata of
/// *the crate we are currently compiling*, which must
/// be a proc-macro crate. This id can be passed to
diff --git a/compiler/rustc_expand/src/tokenstream/tests.rs b/compiler/rustc_expand/src/tokenstream/tests.rs
index eed696810..91c4dd732 100644
--- a/compiler/rustc_expand/src/tokenstream/tests.rs
+++ b/compiler/rustc_expand/src/tokenstream/tests.rs
@@ -1,7 +1,7 @@
use crate::tests::string_to_stream;
use rustc_ast::token;
-use rustc_ast::tokenstream::{TokenStream, TokenStreamBuilder};
+use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_span::create_default_session_globals_then;
use rustc_span::{BytePos, Span, Symbol};
@@ -19,10 +19,9 @@ fn test_concat() {
let test_res = string_to_ts("foo::bar::baz");
let test_fst = string_to_ts("foo::bar");
let test_snd = string_to_ts("::baz");
- let mut builder = TokenStreamBuilder::new();
- builder.push(test_fst);
- builder.push(test_snd);
- let eq_res = builder.build();
+ let mut eq_res = TokenStream::default();
+ eq_res.push_stream(test_fst);
+ eq_res.push_stream(test_snd);
assert_eq!(test_res.trees().count(), 5);
assert_eq!(eq_res.trees().count(), 5);
assert_eq!(test_res.eq_unspanned(&eq_res), true);
@@ -99,11 +98,10 @@ fn test_is_empty() {
#[test]
fn test_dotdotdot() {
create_default_session_globals_then(|| {
- let mut builder = TokenStreamBuilder::new();
- builder.push(TokenStream::token_joint(token::Dot, sp(0, 1)));
- builder.push(TokenStream::token_joint(token::Dot, sp(1, 2)));
- builder.push(TokenStream::token_alone(token::Dot, sp(2, 3)));
- let stream = builder.build();
+ let mut stream = TokenStream::default();
+ stream.push_tree(TokenTree::token_joint(token::Dot, sp(0, 1)));
+ stream.push_tree(TokenTree::token_joint(token::Dot, sp(1, 2)));
+ stream.push_tree(TokenTree::token_alone(token::Dot, sp(2, 3)));
assert!(stream.eq_unspanned(&string_to_ts("...")));
assert_eq!(stream.trees().count(), 1);
})
diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml
index 3d8d0db20..6f6468646 100644
--- a/compiler/rustc_feature/Cargo.toml
+++ b/compiler/rustc_feature/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 8efb7ccc1..80448605c 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -53,6 +53,10 @@ declare_features! (
(accepted, abi_sysv64, "1.24.0", Some(36167), None),
/// Allows using ADX intrinsics from `core::arch::{x86, x86_64}`.
(accepted, adx_target_feature, "1.61.0", Some(44839), None),
+ /// Allows explicit discriminants on non-unit enum variants.
+ (accepted, arbitrary_enum_discriminant, "1.66.0", Some(60553), None),
+ /// Allows using `sym` operands in inline assembly.
+ (accepted, asm_sym, "1.66.0", Some(93333), None),
/// Allows the definition of associated constants in `trait` or `impl` blocks.
(accepted, associated_consts, "1.20.0", Some(29646), None),
/// Allows using associated `type`s in `trait`s.
@@ -169,6 +173,8 @@ declare_features! (
(accepted, global_allocator, "1.28.0", Some(27389), None),
// FIXME: explain `globs`.
(accepted, globs, "1.0.0", None, None),
+ /// Allows using `..=X` as a pattern.
+ (accepted, half_open_range_patterns, "1.66.0", Some(67264), None),
/// Allows using the `u128` and `i128` types.
(accepted, i128_type, "1.26.0", Some(35118), None),
/// Allows the use of `if let` expressions.
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 3aecfba5f..647ccdec7 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -292,16 +292,12 @@ declare_features! (
(incomplete, adt_const_params, "1.56.0", Some(95174), None),
/// Allows defining an `#[alloc_error_handler]`.
(active, alloc_error_handler, "1.29.0", Some(51540), None),
- /// Allows explicit discriminants on non-unit enum variants.
- (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None),
/// Allows trait methods with arbitrary self types.
(active, arbitrary_self_types, "1.23.0", Some(44874), None),
/// Allows using `const` operands in inline assembly.
(active, asm_const, "1.58.0", Some(93332), None),
/// Enables experimental inline assembly support for additional architectures.
(active, asm_experimental_arch, "1.58.0", Some(93335), None),
- /// Allows using `sym` operands in inline assembly.
- (active, asm_sym, "1.58.0", Some(93333), None),
/// Allows the `may_unwind` option in inline assembly.
(active, asm_unwind, "1.58.0", Some(93334), None),
/// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
@@ -312,6 +308,8 @@ declare_features! (
(active, associated_type_defaults, "1.2.0", Some(29661), None),
/// Allows `async || body` closures.
(active, async_closure, "1.37.0", Some(62290), None),
+ /// Alows async functions to be declared, implemented, and used in traits.
+ (incomplete, async_fn_in_trait, "1.66.0", Some(91611), None),
/// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries.
(active, c_unwind, "1.52.0", Some(74990), None),
/// Allows using C-variadics.
@@ -410,8 +408,8 @@ declare_features! (
(incomplete, generic_associated_types_extended, "1.61.0", Some(95451), None),
/// Allows non-trivial generic constants which have to have wfness manually propagated to callers
(incomplete, generic_const_exprs, "1.56.0", Some(76560), None),
- /// Allows using `..X`, `..=X`, `...X`, and `X..` as a pattern.
- (active, half_open_range_patterns, "1.41.0", Some(67264), None),
+ /// Allows using `..=X` as a patterns in slices.
+ (active, half_open_range_patterns_in_slices, "1.66.0", Some(67264), None),
/// Allows `if let` guard in match arms.
(active, if_let_guard, "1.47.0", Some(51114), None),
/// Allows using imported `main` function
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index b50c972e6..2ead3c2c8 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -296,20 +296,24 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// Lints:
ungated!(
- warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+ warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+ DuplicatesOk, @only_local: true,
),
ungated!(
- allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+ allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+ DuplicatesOk, @only_local: true,
),
gated!(
expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk,
lint_reasons, experimental!(expect)
),
ungated!(
- forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+ forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+ DuplicatesOk, @only_local: true,
),
ungated!(
- deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
+ deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+ DuplicatesOk, @only_local: true,
),
ungated!(must_use, Normal, template!(Word, NameValueStr: "reason"), FutureWarnFollowing),
gated!(
@@ -340,7 +344,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(no_link, Normal, template!(Word), WarnFollowing),
- ungated!(repr, Normal, template!(List: "C"), DuplicatesOk),
+ ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, @only_local: true),
ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true),
@@ -382,7 +386,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, @only_local: true),
ungated!(cold, Normal, template!(Word), WarnFollowing, @only_local: true),
ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing),
- ungated!(target_feature, Normal, template!(List: r#"enable = "name""#), DuplicatesOk),
+ ungated!(
+ target_feature, Normal, template!(List: r#"enable = "name""#),
+ DuplicatesOk, @only_local: true,
+ ),
ungated!(track_caller, Normal, template!(Word), WarnFollowing),
gated!(
no_sanitize, Normal,
@@ -468,7 +475,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// RFC 2632
gated!(
const_trait, Normal, template!(Word), WarnFollowing, const_trait_impl,
- "`const` is a temporary placeholder for marking a trait that is suitable for `const` \
+ "`const_trait` is a temporary placeholder for marking a trait that is suitable for `const` \
`impls` and all default bodies as `const`, which may be removed or renamed in the \
future."
),
@@ -488,17 +495,24 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// Internal attributes: Stability, deprecation, and unsafe:
// ==========================================================================
- ungated!(feature, CrateLevel, template!(List: "name1, name2, ..."), DuplicatesOk),
+ ungated!(
+ feature, CrateLevel,
+ template!(List: "name1, name2, ..."), DuplicatesOk, @only_local: true,
+ ),
// DuplicatesOk since it has its own validation
ungated!(
- stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk,
+ stable, Normal,
+ template!(List: r#"feature = "name", since = "version""#), DuplicatesOk, @only_local: true,
),
ungated!(
unstable, Normal,
template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk,
),
ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
- ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
+ ungated!(
+ rustc_const_stable, Normal,
+ template!(List: r#"feature = "name""#), DuplicatesOk, @only_local: true,
+ ),
ungated!(
rustc_default_body_unstable, Normal,
template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk
@@ -516,6 +530,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
"allow_internal_unsafe side-steps the unsafe_code lint",
),
+ ungated!(rustc_safe_intrinsic, Normal, template!(Word), DuplicatesOk),
rustc_attr!(rustc_allowed_through_unstable_modules, Normal, template!(Word), WarnFollowing,
"rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \
through unstable paths"),
@@ -535,7 +550,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// ==========================================================================
rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
- rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
+ rustc_attr!(rustc_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
rustc_attr!(rustc_reallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
rustc_attr!(rustc_deallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
rustc_attr!(rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
@@ -731,7 +746,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
for reserving for `for<T> From<!> for T` impl"
),
rustc_attr!(
- rustc_test_marker, Normal, template!(Word), WarnFollowing,
+ rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing,
"the `#[rustc_test_marker]` attribute is used internally to track tests",
),
rustc_attr!(
@@ -762,7 +777,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// Internal attributes, Testing:
// ==========================================================================
- rustc_attr!(TEST, rustc_access_level, Normal, template!(Word), WarnFollowing),
+ rustc_attr!(TEST, rustc_effective_visibility, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_outlives, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing),
@@ -822,6 +837,8 @@ pub fn is_builtin_attr_name(name: Symbol) -> bool {
BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
}
+/// 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)
}
diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml
index 69ad623b7..129f8d235 100644
--- a/compiler/rustc_hir/Cargo.toml
+++ b/compiler/rustc_hir/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
rustc_arena = { path = "../rustc_arena" }
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index e7c26bd72..4ef4aad90 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -314,74 +314,75 @@ pub enum Res<Id = hir::HirId> {
/// **Belongs to the type namespace.**
PrimTy(hir::PrimTy),
- /// The `Self` type, optionally with the [`DefId`] of the trait it belongs to and
- /// optionally with the [`DefId`] of the item introducing the `Self` type alias.
+ /// The `Self` type, as used within a trait.
+ ///
+ /// **Belongs to the type namespace.**
+ ///
+ /// See the examples on [`Res::SelfTyAlias`] for details.
+ SelfTyParam {
+ /// The trait this `Self` is a generic parameter for.
+ trait_: DefId,
+ },
+
+ /// The `Self` type, as used somewhere other than within a trait.
///
/// **Belongs to the type namespace.**
///
/// Examples:
/// ```
- /// struct Bar(Box<Self>);
- /// // `Res::SelfTy { trait_: None, alias_of: Some(Bar) }`
+ /// struct Bar(Box<Self>); // SelfTyAlias
///
/// trait Foo {
- /// fn foo() -> Box<Self>;
- /// // `Res::SelfTy { trait_: Some(Foo), alias_of: None }`
+ /// fn foo() -> Box<Self>; // SelfTyParam
/// }
///
/// impl Bar {
/// fn blah() {
- /// let _: Self;
- /// // `Res::SelfTy { trait_: None, alias_of: Some(::{impl#0}) }`
+ /// let _: Self; // SelfTyAlias
/// }
/// }
///
/// impl Foo for Bar {
- /// fn foo() -> Box<Self> {
- /// // `Res::SelfTy { trait_: Some(Foo), alias_of: Some(::{impl#1}) }`
- /// let _: Self;
- /// // `Res::SelfTy { trait_: Some(Foo), alias_of: Some(::{impl#1}) }`
+ /// fn foo() -> Box<Self> { // SelfTyAlias
+ /// let _: Self; // SelfTyAlias
///
/// todo!()
/// }
/// }
/// ```
- ///
/// *See also [`Res::SelfCtor`].*
///
- /// -----
- ///
- /// HACK(min_const_generics): self types also have an optional requirement to **not** mention
- /// any generic parameters to allow the following with `min_const_generics`:
- /// ```
- /// # struct Foo;
- /// impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()] { todo!() } }
- ///
- /// struct Bar([u8; baz::<Self>()]);
- /// const fn baz<T>() -> usize { 10 }
- /// ```
- /// We do however allow `Self` in repeat expression even if it is generic to not break code
- /// which already works on stable while causing the `const_evaluatable_unchecked` future compat
- /// lint:
- /// ```
- /// fn foo<T>() {
- /// let _bar = [1_u8; std::mem::size_of::<*mut T>()];
- /// }
- /// ```
- // FIXME(generic_const_exprs): Remove this bodge once that feature is stable.
- SelfTy {
- /// The trait this `Self` is a generic arg for.
- trait_: Option<DefId>,
+ SelfTyAlias {
/// The item introducing the `Self` type alias. Can be used in the `type_of` query
- /// to get the underlying type. Additionally whether the `Self` type is disallowed
- /// from mentioning generics (i.e. when used in an anonymous constant).
- alias_to: Option<(DefId, bool)>,
- },
+ /// to get the underlying type.
+ alias_to: DefId,
- /// A tool attribute module; e.g., the `rustfmt` in `#[rustfmt::skip]`.
- ///
- /// **Belongs to the type namespace.**
- ToolMod,
+ /// Whether the `Self` type is disallowed from mentioning generics (i.e. when used in an
+ /// anonymous constant).
+ ///
+ /// HACK(min_const_generics): self types also have an optional requirement to **not**
+ /// mention any generic parameters to allow the following with `min_const_generics`:
+ /// ```
+ /// # struct Foo;
+ /// impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()] { todo!() } }
+ ///
+ /// struct Bar([u8; baz::<Self>()]);
+ /// const fn baz<T>() -> usize { 10 }
+ /// ```
+ /// We do however allow `Self` in repeat expression even if it is generic to not break code
+ /// which already works on stable while causing the `const_evaluatable_unchecked` future
+ /// compat lint:
+ /// ```
+ /// fn foo<T>() {
+ /// let _bar = [1_u8; std::mem::size_of::<*mut T>()];
+ /// }
+ /// ```
+ // FIXME(generic_const_exprs): Remove this bodge once that feature is stable.
+ forbid_generic: bool,
+
+ /// Is this within an `impl Foo for bar`?
+ is_trait_impl: bool,
+ },
// Value namespace
/// The `Self` constructor, along with the [`DefId`]
@@ -389,7 +390,7 @@ pub enum Res<Id = hir::HirId> {
///
/// **Belongs to the value namespace.**
///
- /// *See also [`Res::SelfTy`].*
+ /// *See also [`Res::SelfTyParam`] and [`Res::SelfTyAlias`].*
SelfCtor(DefId),
/// A local variable or function parameter.
@@ -397,6 +398,11 @@ pub enum Res<Id = hir::HirId> {
/// **Belongs to the value namespace.**
Local(Id),
+ /// A tool attribute module; e.g., the `rustfmt` in `#[rustfmt::skip]`.
+ ///
+ /// **Belongs to the type namespace.**
+ ToolMod,
+
// Macro namespace
/// An attribute that is *not* implemented via macro.
/// E.g., `#[inline]` and `#[rustfmt::skip]`, which are essentially directives,
@@ -458,6 +464,16 @@ impl PartialRes {
pub fn unresolved_segments(&self) -> usize {
self.unresolved_segments
}
+
+ #[inline]
+ pub fn full_res(&self) -> Option<Res<NodeId>> {
+ (self.unresolved_segments == 0).then_some(self.base_res)
+ }
+
+ #[inline]
+ pub fn expect_full_res(&self) -> Res<NodeId> {
+ self.full_res().expect("unexpected unresolved segments")
+ }
}
/// Different kinds of symbols can coexist even if they share the same textual name.
@@ -606,7 +622,8 @@ impl<Id> Res<Id> {
Res::Local(..)
| Res::PrimTy(..)
- | Res::SelfTy { .. }
+ | Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. }
| Res::SelfCtor(..)
| Res::ToolMod
| Res::NonMacroAttr(..)
@@ -629,7 +646,7 @@ impl<Id> Res<Id> {
Res::SelfCtor(..) => "self constructor",
Res::PrimTy(..) => "builtin type",
Res::Local(..) => "local variable",
- Res::SelfTy { .. } => "self type",
+ Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => "self type",
Res::ToolMod => "tool module",
Res::NonMacroAttr(attr_kind) => attr_kind.descr(),
Res::Err => "unresolved item",
@@ -652,7 +669,10 @@ impl<Id> Res<Id> {
Res::SelfCtor(id) => Res::SelfCtor(id),
Res::PrimTy(id) => Res::PrimTy(id),
Res::Local(id) => Res::Local(map(id)),
- Res::SelfTy { trait_, alias_to } => Res::SelfTy { trait_, alias_to },
+ Res::SelfTyParam { trait_ } => Res::SelfTyParam { trait_ },
+ Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl } => {
+ Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl }
+ }
Res::ToolMod => Res::ToolMod,
Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
Res::Err => Res::Err,
@@ -665,7 +685,10 @@ impl<Id> Res<Id> {
Res::SelfCtor(id) => Res::SelfCtor(id),
Res::PrimTy(id) => Res::PrimTy(id),
Res::Local(id) => Res::Local(map(id)?),
- Res::SelfTy { trait_, alias_to } => Res::SelfTy { trait_, alias_to },
+ Res::SelfTyParam { trait_ } => Res::SelfTyParam { trait_ },
+ Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl } => {
+ Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl }
+ }
Res::ToolMod => Res::ToolMod,
Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
Res::Err => Res::Err,
@@ -692,7 +715,9 @@ impl<Id> Res<Id> {
pub fn ns(&self) -> Option<Namespace> {
match self {
Res::Def(kind, ..) => kind.ns(),
- Res::PrimTy(..) | Res::SelfTy { .. } | Res::ToolMod => Some(Namespace::TypeNS),
+ Res::PrimTy(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::ToolMod => {
+ Some(Namespace::TypeNS)
+ }
Res::SelfCtor(..) | Res::Local(..) => Some(Namespace::ValueNS),
Res::NonMacroAttr(..) => Some(Namespace::MacroNS),
Res::Err => None,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index a8436ea64..ef00c1ffc 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1,6 +1,6 @@
use crate::def::{CtorKind, DefKind, Res};
use crate::def_id::DefId;
-pub(crate) use crate::hir_id::{HirId, ItemLocalId};
+pub(crate) use crate::hir_id::{HirId, ItemLocalId, OwnerId};
use crate::intravisit::FnKind;
use crate::LangItem;
@@ -731,6 +731,7 @@ pub enum PredicateOrigin {
/// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
#[derive(Debug, HashStable_Generic)]
pub struct WhereBoundPredicate<'hir> {
+ pub hir_id: HirId,
pub span: Span,
/// Origin of the predicate.
pub origin: PredicateOrigin,
@@ -2206,14 +2207,14 @@ pub struct FnSig<'hir> {
// so it can fetched later.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct TraitItemId {
- pub def_id: LocalDefId,
+ pub owner_id: OwnerId,
}
impl TraitItemId {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
}
@@ -2224,7 +2225,7 @@ impl TraitItemId {
#[derive(Debug, HashStable_Generic)]
pub struct TraitItem<'hir> {
pub ident: Ident,
- pub def_id: LocalDefId,
+ pub owner_id: OwnerId,
pub generics: &'hir Generics<'hir>,
pub kind: TraitItemKind<'hir>,
pub span: Span,
@@ -2235,11 +2236,11 @@ impl TraitItem<'_> {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
pub fn trait_item_id(&self) -> TraitItemId {
- TraitItemId { def_id: self.def_id }
+ TraitItemId { owner_id: self.owner_id }
}
}
@@ -2270,14 +2271,14 @@ pub enum TraitItemKind<'hir> {
// so it can fetched later.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct ImplItemId {
- pub def_id: LocalDefId,
+ pub owner_id: OwnerId,
}
impl ImplItemId {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
}
@@ -2285,7 +2286,7 @@ impl ImplItemId {
#[derive(Debug, HashStable_Generic)]
pub struct ImplItem<'hir> {
pub ident: Ident,
- pub def_id: LocalDefId,
+ pub owner_id: OwnerId,
pub generics: &'hir Generics<'hir>,
pub kind: ImplItemKind<'hir>,
pub defaultness: Defaultness,
@@ -2297,11 +2298,11 @@ impl ImplItem<'_> {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
pub fn impl_item_id(&self) -> ImplItemId {
- ImplItemId { def_id: self.def_id }
+ ImplItemId { owner_id: self.owner_id }
}
}
@@ -2314,7 +2315,7 @@ pub enum ImplItemKind<'hir> {
/// An associated function implementation with the given signature and body.
Fn(FnSig<'hir>, BodyId),
/// An associated type.
- TyAlias(&'hir Ty<'hir>),
+ Type(&'hir Ty<'hir>),
}
// The name of the associated type for `Fn` return types.
@@ -2403,8 +2404,9 @@ impl<'hir> Ty<'hir> {
return None;
};
match path.res {
- Res::Def(DefKind::TyParam, def_id)
- | Res::SelfTy { trait_: Some(def_id), alias_to: None } => Some((def_id, segment.ident)),
+ Res::Def(DefKind::TyParam, def_id) | Res::SelfTyParam { trait_: def_id } => {
+ Some((def_id, segment.ident))
+ }
_ => None,
}
}
@@ -2416,6 +2418,30 @@ impl<'hir> Ty<'hir> {
}
final_ty
}
+
+ pub fn find_self_aliases(&self) -> Vec<Span> {
+ use crate::intravisit::Visitor;
+ struct MyVisitor(Vec<Span>);
+ impl<'v> Visitor<'v> for MyVisitor {
+ fn visit_ty(&mut self, t: &'v Ty<'v>) {
+ if matches!(
+ &t.kind,
+ TyKind::Path(QPath::Resolved(
+ _,
+ Path { res: crate::def::Res::SelfTyAlias { .. }, .. },
+ ))
+ ) {
+ self.0.push(t.span);
+ return;
+ }
+ crate::intravisit::walk_ty(self, t);
+ }
+ }
+
+ let mut my_visitor = MyVisitor(vec![]);
+ my_visitor.visit_ty(self);
+ my_visitor.0
+ }
}
/// Not represented directly in the AST; referred to by name through a `ty_path`.
@@ -2888,14 +2914,14 @@ impl<'hir> VariantData<'hir> {
// so it can fetched later.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash, HashStable_Generic)]
pub struct ItemId {
- pub def_id: LocalDefId,
+ pub owner_id: OwnerId,
}
impl ItemId {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
}
@@ -2905,7 +2931,7 @@ impl ItemId {
#[derive(Debug, HashStable_Generic)]
pub struct Item<'hir> {
pub ident: Ident,
- pub def_id: LocalDefId,
+ pub owner_id: OwnerId,
pub kind: ItemKind<'hir>,
pub span: Span,
pub vis_span: Span,
@@ -2915,11 +2941,11 @@ impl Item<'_> {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
pub fn item_id(&self) -> ItemId {
- ItemId { def_id: self.def_id }
+ ItemId { owner_id: self.owner_id }
}
}
@@ -3132,14 +3158,14 @@ pub enum AssocItemKind {
// so it can fetched later.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct ForeignItemId {
- pub def_id: LocalDefId,
+ pub owner_id: OwnerId,
}
impl ForeignItemId {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
}
@@ -3160,7 +3186,7 @@ pub struct ForeignItemRef {
pub struct ForeignItem<'hir> {
pub ident: Ident,
pub kind: ForeignItemKind<'hir>,
- pub def_id: LocalDefId,
+ pub owner_id: OwnerId,
pub span: Span,
pub vis_span: Span,
}
@@ -3169,11 +3195,11 @@ impl ForeignItem<'_> {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
pub fn foreign_item_id(&self) -> ForeignItemId {
- ForeignItemId { def_id: self.def_id }
+ ForeignItemId { owner_id: self.owner_id }
}
}
@@ -3263,12 +3289,12 @@ impl<'hir> OwnerNode<'hir> {
Node::generics(self.into())
}
- pub fn def_id(self) -> LocalDefId {
+ pub fn def_id(self) -> OwnerId {
match self {
- OwnerNode::Item(Item { def_id, .. })
- | OwnerNode::TraitItem(TraitItem { def_id, .. })
- | OwnerNode::ImplItem(ImplItem { def_id, .. })
- | OwnerNode::ForeignItem(ForeignItem { def_id, .. }) => *def_id,
+ OwnerNode::Item(Item { owner_id, .. })
+ | OwnerNode::TraitItem(TraitItem { owner_id, .. })
+ | OwnerNode::ImplItem(ImplItem { owner_id, .. })
+ | OwnerNode::ForeignItem(ForeignItem { owner_id, .. }) => *owner_id,
OwnerNode::Crate(..) => crate::CRATE_HIR_ID.owner,
}
}
@@ -3512,7 +3538,7 @@ impl<'hir> Node<'hir> {
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
mod size_asserts {
use super::*;
- // These are in alphabetical order, which is easy to maintain.
+ // tidy-alphabetical-start
static_assert_size!(Block<'_>, 48);
static_assert_size!(Body<'_>, 32);
static_assert_size!(Expr<'_>, 64);
@@ -3520,30 +3546,27 @@ mod size_asserts {
static_assert_size!(FnDecl<'_>, 40);
static_assert_size!(ForeignItem<'_>, 72);
static_assert_size!(ForeignItemKind<'_>, 40);
- #[cfg(not(bootstrap))]
static_assert_size!(GenericArg<'_>, 24);
static_assert_size!(GenericBound<'_>, 48);
static_assert_size!(Generics<'_>, 56);
static_assert_size!(Impl<'_>, 80);
- #[cfg(not(bootstrap))]
static_assert_size!(ImplItem<'_>, 80);
- #[cfg(not(bootstrap))]
static_assert_size!(ImplItemKind<'_>, 32);
static_assert_size!(Item<'_>, 80);
static_assert_size!(ItemKind<'_>, 48);
static_assert_size!(Local<'_>, 64);
static_assert_size!(Param<'_>, 32);
static_assert_size!(Pat<'_>, 72);
+ static_assert_size!(Path<'_>, 40);
+ static_assert_size!(PathSegment<'_>, 48);
static_assert_size!(PatKind<'_>, 48);
- static_assert_size!(Path<'_>, 48);
- static_assert_size!(PathSegment<'_>, 56);
static_assert_size!(QPath<'_>, 24);
+ static_assert_size!(Res, 12);
static_assert_size!(Stmt<'_>, 32);
static_assert_size!(StmtKind<'_>, 16);
- #[cfg(not(bootstrap))]
static_assert_size!(TraitItem<'_>, 88);
- #[cfg(not(bootstrap))]
static_assert_size!(TraitItemKind<'_>, 48);
static_assert_size!(Ty<'_>, 48);
static_assert_size!(TyKind<'_>, 32);
+ // tidy-alphabetical-end
}
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index 84b0740c7..752f760ea 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -1,6 +1,43 @@
-use crate::def_id::{LocalDefId, CRATE_DEF_ID};
+use crate::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_span::{def_id::DefPathHash, HashStableContext};
use std::fmt;
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Encodable, Decodable)]
+pub struct OwnerId {
+ pub def_id: LocalDefId,
+}
+
+impl From<OwnerId> for HirId {
+ fn from(owner: OwnerId) -> HirId {
+ HirId { owner, local_id: ItemLocalId::from_u32(0) }
+ }
+}
+
+impl OwnerId {
+ #[inline]
+ pub fn to_def_id(self) -> DefId {
+ self.def_id.to_def_id()
+ }
+}
+
+impl<CTX: HashStableContext> HashStable<CTX> for OwnerId {
+ #[inline]
+ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+ self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
+ }
+}
+
+impl<CTX: HashStableContext> ToStableHashKey<CTX> for OwnerId {
+ type KeyType = DefPathHash;
+
+ #[inline]
+ fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
+ hcx.def_path_hash(self.to_def_id())
+ }
+}
+
/// Uniquely identifies a node in the HIR of the current crate. It is
/// composed of the `owner`, which is the `LocalDefId` of the directly enclosing
/// `hir::Item`, `hir::TraitItem`, or `hir::ImplItem` (i.e., the closest "item-like"),
@@ -15,22 +52,23 @@ use std::fmt;
#[derive(Encodable, Decodable, HashStable_Generic)]
#[rustc_pass_by_value]
pub struct HirId {
- pub owner: LocalDefId,
+ pub owner: OwnerId,
pub local_id: ItemLocalId,
}
impl HirId {
/// Signal local id which should never be used.
- pub const INVALID: HirId = HirId { owner: CRATE_DEF_ID, local_id: ItemLocalId::INVALID };
+ pub const INVALID: HirId =
+ HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::INVALID };
#[inline]
- pub fn expect_owner(self) -> LocalDefId {
+ pub fn expect_owner(self) -> OwnerId {
assert_eq!(self.local_id.index(), 0);
self.owner
}
#[inline]
- pub fn as_owner(self) -> Option<LocalDefId> {
+ pub fn as_owner(self) -> Option<OwnerId> {
if self.local_id.index() == 0 { Some(self.owner) } else { None }
}
@@ -41,11 +79,14 @@ impl HirId {
#[inline]
pub fn make_owner(owner: LocalDefId) -> Self {
- Self { owner, local_id: ItemLocalId::from_u32(0) }
+ Self { owner: OwnerId { def_id: owner }, local_id: ItemLocalId::from_u32(0) }
}
pub fn index(self) -> (usize, usize) {
- (rustc_index::vec::Idx::index(self.owner), rustc_index::vec::Idx::index(self.local_id))
+ (
+ rustc_index::vec::Idx::index(self.owner.def_id),
+ rustc_index::vec::Idx::index(self.local_id),
+ )
}
}
@@ -94,4 +135,7 @@ impl ItemLocalId {
}
/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
-pub const CRATE_HIR_ID: HirId = HirId { owner: CRATE_DEF_ID, local_id: ItemLocalId::from_u32(0) };
+pub const CRATE_HIR_ID: HirId =
+ HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::from_u32(0) };
+
+pub const CRATE_OWNER_ID: OwnerId = OwnerId { def_id: CRATE_DEF_ID };
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 8f5f314ec..be77e6fd3 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -847,20 +847,28 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
) {
match *predicate {
WherePredicate::BoundPredicate(WhereBoundPredicate {
+ hir_id,
ref bounded_ty,
bounds,
bound_generic_params,
- ..
+ origin: _,
+ span: _,
}) => {
+ visitor.visit_id(hir_id);
visitor.visit_ty(bounded_ty);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_generic_param, bound_generic_params);
}
- WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime, bounds, .. }) => {
+ WherePredicate::RegionPredicate(WhereRegionPredicate {
+ ref lifetime,
+ bounds,
+ span: _,
+ in_where_clause: _,
+ }) => {
visitor.visit_lifetime(lifetime);
walk_list!(visitor, visit_param_bound, bounds);
}
- WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, .. }) => {
+ WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, span: _ }) => {
visitor.visit_ty(lhs_ty);
visitor.visit_ty(rhs_ty);
}
@@ -904,7 +912,7 @@ pub fn walk_fn<'v, V: Visitor<'v>>(
pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem<'v>) {
// N.B., deliberately force a compilation error if/when new fields are added.
- let TraitItem { ident, generics, ref defaultness, ref kind, span, def_id: _ } = *trait_item;
+ let TraitItem { ident, generics, ref defaultness, ref kind, span, owner_id: _ } = *trait_item;
let hir_id = trait_item.hir_id();
visitor.visit_ident(ident);
visitor.visit_generics(&generics);
@@ -944,7 +952,7 @@ pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref:
pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem<'v>) {
// N.B., deliberately force a compilation error if/when new fields are added.
let ImplItem {
- def_id: _,
+ owner_id: _,
ident,
ref generics,
ref kind,
@@ -971,7 +979,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
impl_item.hir_id(),
);
}
- ImplItemKind::TyAlias(ref ty) => {
+ ImplItemKind::Type(ref ty) => {
visitor.visit_id(impl_item.hir_id());
visitor.visit_ty(ty);
}
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 946da9265..1c4aa420c 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -4,8 +4,7 @@
#![feature(associated_type_defaults)]
#![feature(closure_track_caller)]
-#![feature(const_btree_new)]
-#![cfg_attr(bootstrap, feature(let_else))]
+#![feature(const_btree_len)]
#![feature(once_cell)]
#![feature(min_specialization)]
#![feature(never_type)]
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index 5b9c42686..23423e8f3 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -20,7 +20,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
- let def_path_hash = self.owner.to_stable_hash_key(hcx);
+ let def_path_hash = self.owner.def_id.to_stable_hash_key(hcx);
(def_path_hash, self.local_id)
}
}
@@ -49,7 +49,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ItemId {
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
- self.def_id.to_stable_hash_key(hcx)
+ self.owner_id.def_id.to_stable_hash_key(hcx)
}
}
@@ -58,7 +58,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for TraitItemId {
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
- self.def_id.to_stable_hash_key(hcx)
+ self.owner_id.def_id.to_stable_hash_key(hcx)
}
}
@@ -67,7 +67,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ImplItemId {
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
- self.def_id.to_stable_hash_key(hcx)
+ self.owner_id.def_id.to_stable_hash_key(hcx)
}
}
@@ -76,7 +76,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ForeignItemId
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
- self.def_id.to_stable_hash_key(hcx)
+ self.owner_id.def_id.to_stable_hash_key(hcx)
}
}
diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml
index cae29c1d3..0761d8cdb 100644
--- a/compiler/rustc_typeck/Cargo.toml
+++ b/compiler/rustc_hir_analysis/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "rustc_typeck"
+name = "rustc_hir_analysis"
version = "0.0.0"
edition = "2021"
@@ -26,7 +26,6 @@ rustc_span = { path = "../rustc_span" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
-rustc_ty_utils = { path = "../rustc_ty_utils" }
rustc_lint = { path = "../rustc_lint" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_typeck/README.md b/compiler/rustc_hir_analysis/README.md
index b61dbd8c9..b61dbd8c9 100644
--- a/compiler/rustc_typeck/README.md
+++ b/compiler/rustc_hir_analysis/README.md
diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index a9152bdc5..a9152bdc5 100644
--- a/compiler/rustc_typeck/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index afac75de2..47915b4bd 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -83,9 +83,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Res::Def(DefKind::TyParam, src_def_id) => {
if let Some(param_local_id) = param.def_id.as_local() {
let param_name = tcx.hir().ty_param_name(param_local_id);
- let param_type = tcx.infer_ctxt().enter(|infcx| {
- infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id))
- });
+ let infcx = tcx.infer_ctxt().build();
+ let param_type =
+ infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id));
if param_type.is_suggestable(tcx, false) {
err.span_suggestion(
tcx.def_span(src_def_id),
@@ -448,8 +448,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let infer_lifetimes =
(gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
- if gen_pos != GenericArgPosition::Type && !gen_args.bindings.is_empty() {
- Self::prohibit_assoc_ty_binding(tcx, gen_args.bindings[0].span);
+ if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() {
+ Self::prohibit_assoc_ty_binding(tcx, b.span);
}
let explicit_late_bound =
@@ -649,9 +649,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
LATE_BOUND_LIFETIME_ARGUMENTS,
args.args[0].hir_id(),
multispan,
- |lint| {
- lint.build(msg).emit();
- },
+ msg,
+ |lint| lint,
);
}
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 4bf9562e2..38f195dab 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -26,7 +26,7 @@ use rustc_hir::intravisit::{walk_generics, Visitor as _};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
use rustc_middle::middle::stability::AllowUnstable;
-use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
+use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
use rustc_middle::ty::DynKind;
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{
@@ -36,7 +36,7 @@ use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECT
use rustc_span::edition::Edition;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
use rustc_target::spec::abi;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::astconv_object_safety_violations;
@@ -275,10 +275,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
item_segment.args(),
item_segment.infer_args,
None,
+ None,
);
- let assoc_bindings = self.create_assoc_bindings_for_generic_args(item_segment.args());
-
- if let Some(b) = assoc_bindings.first() {
+ if let Some(b) = item_segment.args().bindings.first() {
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
}
@@ -326,6 +325,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
generic_args: &'a hir::GenericArgs<'_>,
infer_args: bool,
self_ty: Option<Ty<'tcx>>,
+ constness: Option<ty::BoundConstness>,
) -> (SubstsRef<'tcx>, GenericArgCountResult) {
// If the type is parameterized by this region, then replace this
// region with the current anon region binding (in other words,
@@ -365,7 +365,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// here and so associated type bindings will be handled regardless of whether there are any
// non-`Self` generic parameters.
if generics.params.is_empty() {
- return (tcx.intern_substs(&[]), arg_count);
+ return (tcx.intern_substs(parent_substs), arg_count);
}
struct SubstsForAstPathCtxt<'a, 'tcx> {
@@ -536,6 +536,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&mut substs_ctx,
);
+ if let Some(ty::BoundConstness::ConstIfConst) = constness
+ && generics.has_self && !tcx.has_attr(def_id, sym::const_trait)
+ {
+ tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span } );
+ }
+
(substs, arg_count)
}
@@ -584,9 +590,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
assoc_bindings
}
- pub(crate) fn create_substs_for_associated_item(
+ pub fn create_substs_for_associated_item(
&self,
- tcx: TyCtxt<'tcx>,
span: Span,
item_def_id: DefId,
item_segment: &hir::PathSegment<'_>,
@@ -596,28 +601,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
"create_substs_for_associated_item(span: {:?}, item_def_id: {:?}, item_segment: {:?}",
span, item_def_id, item_segment
);
- if tcx.generics_of(item_def_id).params.is_empty() {
- self.prohibit_generics(slice::from_ref(item_segment).iter(), |_| {});
-
- parent_substs
- } else {
- let (args, _) = self.create_substs_for_ast_path(
- span,
- item_def_id,
- parent_substs,
- item_segment,
- item_segment.args(),
- item_segment.infer_args,
- None,
- );
-
- let assoc_bindings = self.create_assoc_bindings_for_generic_args(item_segment.args());
- if let Some(b) = assoc_bindings.first() {
- Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
- }
+ let (args, _) = self.create_substs_for_ast_path(
+ span,
+ item_def_id,
+ parent_substs,
+ item_segment,
+ item_segment.args(),
+ item_segment.infer_args,
+ None,
+ None,
+ );
- args
+ if let Some(b) = item_segment.args().bindings.first() {
+ Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
}
+
+ args
}
/// Instantiates the path for the given trait reference, assuming that it's
@@ -630,6 +629,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&self,
trait_ref: &hir::TraitRef<'_>,
self_ty: Ty<'tcx>,
+ constness: ty::BoundConstness,
) -> ty::TraitRef<'tcx> {
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
@@ -639,6 +639,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty,
trait_ref.path.segments.last().unwrap(),
true,
+ Some(constness),
)
}
@@ -665,6 +666,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
args,
infer_args,
Some(self_ty),
+ Some(constness),
);
let tcx = self.tcx();
@@ -690,6 +692,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
speculative,
&mut dup_bindings,
binding_span.unwrap_or(binding.span),
+ constness,
);
// Okay to ignore `Err` because of `ErrorGuaranteed` (see above).
}
@@ -793,6 +796,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty: Ty<'tcx>,
trait_segment: &hir::PathSegment<'_>,
is_impl: bool,
+ constness: Option<ty::BoundConstness>,
) -> ty::TraitRef<'tcx> {
let (substs, _) = self.create_substs_for_ast_trait_ref(
span,
@@ -800,9 +804,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty,
trait_segment,
is_impl,
+ constness,
);
- let assoc_bindings = self.create_assoc_bindings_for_generic_args(trait_segment.args());
- if let Some(b) = assoc_bindings.first() {
+ if let Some(b) = trait_segment.args().bindings.first() {
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
}
ty::TraitRef::new(trait_def_id, substs)
@@ -816,6 +820,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty: Ty<'tcx>,
trait_segment: &'a hir::PathSegment<'a>,
is_impl: bool,
+ constness: Option<ty::BoundConstness>,
) -> (SubstsRef<'tcx>, GenericArgCountResult) {
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
@@ -827,6 +832,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
trait_segment.args(),
trait_segment.infer_args,
Some(self_ty),
+ constness,
)
}
@@ -1038,6 +1044,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
speculative: bool,
dup_bindings: &mut FxHashMap<DefId, Span>,
path_span: Span,
+ constness: ty::BoundConstness,
) -> Result<(), ErrorGuaranteed> {
// Given something like `U: SomeTrait<T = X>`, we want to produce a
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
@@ -1127,17 +1134,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
- tcx,
path_span,
assoc_item.def_id,
&item_segment,
trait_ref.substs,
);
- debug!(
- "add_predicates_for_ast_type_binding: substs for trait-ref and assoc_item: {:?}",
- substs_trait_ref_and_assoc_item
- );
+ debug!(?substs_trait_ref_and_assoc_item);
ty::ProjectionTy {
item_def_id: assoc_item.def_id,
@@ -1158,8 +1161,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
tcx.collect_constrained_late_bound_regions(&projection_ty);
let late_bound_in_ty =
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty));
- debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
- debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
+ debug!(?late_bound_in_trait_ref);
+ debug!(?late_bound_in_ty);
// FIXME: point at the type params that don't have appropriate lifetimes:
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
@@ -1660,6 +1663,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Checks that `bounds` contains exactly one element and reports appropriate
// errors otherwise.
+ #[instrument(level = "debug", skip(self, all_candidates, ty_param_name, is_equality), ret)]
fn one_bound_for_assoc_type<I>(
&self,
all_candidates: impl Fn() -> I,
@@ -1689,10 +1693,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
return Err(reported);
}
};
- debug!("one_bound_for_assoc_type: bound = {:?}", bound);
+ debug!(?bound);
if let Some(bound2) = next_cand {
- debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
+ debug!(?bound2);
let is_equality = is_equality();
let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates);
@@ -1788,6 +1792,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// parameter or `Self`.
// NOTE: When this function starts resolving `Trait::AssocTy` successfully
// it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
+ #[instrument(level = "debug", skip(self, hir_ref_id, span, qself, assoc_segment), fields(assoc_ident=?assoc_segment.ident), ret)]
pub fn associated_path_to_ty(
&self,
hir_ref_id: hir::HirId,
@@ -1805,8 +1810,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Res::Err
};
- debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident);
-
// Check if we have an enum variant.
let mut variant_resolution = None;
if let ty::Adt(adt_def, _) = qself_ty.kind() {
@@ -1910,7 +1913,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Find the type of the associated item, and the trait where the associated
// item is declared.
let bound = match (&qself_ty.kind(), qself_res) {
- (_, Res::SelfTy { trait_: Some(_), alias_to: Some((impl_def_id, _)) }) => {
+ (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
// `Self` in an impl of a trait -- we have a concrete self type and a
// trait reference.
let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
@@ -1929,8 +1932,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
(
&ty::Param(_),
- Res::SelfTy { trait_: Some(param_did), alias_to: None }
- | Res::Def(DefKind::TyParam, param_did),
+ Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
) => self.find_bound_for_assoc_item(param_did.expect_local(), assoc_ident, span)?,
_ => {
let reported = if variant_resolution.is_some() {
@@ -2023,30 +2025,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
tcx.check_stability(item.def_id, Some(hir_ref_id), span, None);
if let Some(variant_def_id) = variant_resolution {
- tcx.struct_span_lint_hir(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
- let mut err = lint.build("ambiguous associated item");
- let mut could_refer_to = |kind: DefKind, def_id, also| {
- let note_msg = format!(
- "`{}` could{} refer to the {} defined here",
- assoc_ident,
- also,
- kind.descr(def_id)
- );
- err.span_note(tcx.def_span(def_id), &note_msg);
- };
+ tcx.struct_span_lint_hir(
+ AMBIGUOUS_ASSOCIATED_ITEMS,
+ hir_ref_id,
+ span,
+ "ambiguous associated item",
+ |lint| {
+ let mut could_refer_to = |kind: DefKind, def_id, also| {
+ let note_msg = format!(
+ "`{}` could{} refer to the {} defined here",
+ assoc_ident,
+ also,
+ kind.descr(def_id)
+ );
+ lint.span_note(tcx.def_span(def_id), &note_msg);
+ };
- could_refer_to(DefKind::Variant, variant_def_id, "");
- could_refer_to(kind, item.def_id, " also");
+ could_refer_to(DefKind::Variant, variant_def_id, "");
+ could_refer_to(kind, item.def_id, " also");
- err.span_suggestion(
- span,
- "use fully-qualified syntax",
- format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
- Applicability::MachineApplicable,
- );
+ lint.span_suggestion(
+ span,
+ "use fully-qualified syntax",
+ format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
+ Applicability::MachineApplicable,
+ );
- err.emit();
- });
+ lint
+ },
+ );
}
Ok((ty, kind, item.def_id))
}
@@ -2058,6 +2065,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
item_def_id: DefId,
trait_segment: &hir::PathSegment<'_>,
item_segment: &hir::PathSegment<'_>,
+ constness: ty::BoundConstness,
) -> Ty<'tcx> {
let tcx = self.tcx();
@@ -2102,11 +2110,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
debug!("qpath_to_ty: self_type={:?}", self_ty);
- let trait_ref =
- self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false);
+ let trait_ref = self.ast_path_to_mono_trait_ref(
+ span,
+ trait_def_id,
+ self_ty,
+ trait_segment,
+ false,
+ Some(constness),
+ );
let item_substs = self.create_substs_for_associated_item(
- tcx,
span,
item_def_id,
item_segment,
@@ -2217,8 +2230,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
for segment in segments {
// Only emit the first error to avoid overloading the user with error messages.
- if let [binding, ..] = segment.args().bindings {
- Self::prohibit_assoc_ty_binding(self.tcx(), binding.span);
+ if let Some(b) = segment.args().bindings.first() {
+ Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
return true;
}
}
@@ -2426,7 +2439,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let index = generics.param_def_id_to_index[&def_id.to_def_id()];
tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id))
}
- Res::SelfTy { trait_: Some(_), alias_to: None } => {
+ Res::SelfTyParam { .. } => {
// `Self` in trait or type alias.
assert_eq!(opt_self_ty, None);
self.prohibit_generics(path.segments.iter(), |err| {
@@ -2441,7 +2454,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
});
tcx.types.self_param
}
- Res::SelfTy { trait_: _, alias_to: Some((def_id, forbid_generic)) } => {
+ Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => {
// `Self` in impl (we know the concrete type).
assert_eq!(opt_self_ty, None);
// Try to evaluate any array length constants.
@@ -2543,12 +2556,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Res::Def(DefKind::AssocTy, def_id) => {
debug_assert!(path.segments.len() >= 2);
self.prohibit_generics(path.segments[..path.segments.len() - 2].iter(), |_| {});
+ // HACK: until we support `<Type as ~const Trait>`, assume all of them are.
+ let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
+ ty::BoundConstness::ConstIfConst
+ } else {
+ ty::BoundConstness::NotConst
+ };
self.qpath_to_ty(
span,
opt_self_ty,
def_id,
&path.segments[path.segments.len() - 2],
path.segments.last().unwrap(),
+ constness,
)
}
Res::PrimTy(prim_ty) => {
@@ -2641,7 +2661,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
let opaque_ty = tcx.hir().item(item_id);
- let def_id = item_id.def_id.to_def_id();
+ let def_id = item_id.owner_id.to_def_id();
match opaque_ty.kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
@@ -2667,6 +2687,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&GenericArgs::none(),
true,
None,
+ None,
);
EarlyBinder(self.normalize_ty(span, tcx.at(span).type_of(def_id)))
.subst(tcx, substs)
@@ -2775,6 +2796,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
+ #[instrument(level = "debug", skip(self, hir_id, unsafety, abi, decl, generics, hir_ty), ret)]
pub fn ty_of_fn(
&self,
hir_id: hir::HirId,
@@ -2784,8 +2806,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
generics: Option<&hir::Generics<'_>>,
hir_ty: Option<&hir::Ty<'_>>,
) -> ty::PolyFnSig<'tcx> {
- debug!("ty_of_fn");
-
let tcx = self.tcx();
let bound_vars = tcx.late_bound_vars(hir_id);
debug!(?bound_vars);
@@ -2835,7 +2855,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(),
};
- debug!("ty_of_fn: output_ty={:?}", output_ty);
+ debug!(?output_ty);
let fn_ty = tcx.mk_fn_sig(input_tys.into_iter(), output_ty, decl.c_variadic, unsafety, abi);
let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
@@ -2912,8 +2932,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) =
hir.get(hir.get_parent_node(fn_hir_id)) else { bug!("ImplItem should have Impl parent") };
- let trait_ref =
- self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty));
+ let trait_ref = self.instantiate_mono_trait_ref(
+ i.of_trait.as_ref()?,
+ self.ast_ty_to_ty(i.self_ty),
+ ty::BoundConstness::NotConst,
+ );
let assoc = tcx.associated_items(trait_ref.def_id).find_by_name_and_kind(
tcx,
@@ -3009,7 +3032,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// Make sure that we are in the condition to suggest the blanket implementation.
fn maybe_lint_blanket_trait_impl(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) {
let tcx = self.tcx();
- let parent_id = tcx.hir().get_parent_item(self_ty.hir_id);
+ let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
if let hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Impl(hir::Impl {
@@ -3060,24 +3083,27 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.map_or(false, |s| s.trim_end().ends_with('<'));
let is_global = poly_trait_ref.trait_ref.path.is_global();
- let sugg = Vec::from_iter([
- (
- self_ty.span.shrink_to_lo(),
- format!(
- "{}dyn {}",
- if needs_bracket { "<" } else { "" },
- if is_global { "(" } else { "" },
- ),
+
+ let mut sugg = Vec::from_iter([(
+ self_ty.span.shrink_to_lo(),
+ format!(
+ "{}dyn {}",
+ if needs_bracket { "<" } else { "" },
+ if is_global { "(" } else { "" },
),
- (
+ )]);
+
+ if is_global || needs_bracket {
+ sugg.push((
self_ty.span.shrink_to_hi(),
format!(
"{}{}",
if is_global { ")" } else { "" },
if needs_bracket { ">" } else { "" },
),
- ),
- ]);
+ ));
+ }
+
if self_ty.span.edition() >= Edition::Edition2021 {
let msg = "trait objects must include the `dyn` keyword";
let label = "add `dyn` keyword before this trait";
@@ -3093,15 +3119,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
BARE_TRAIT_OBJECTS,
self_ty.hir_id,
self_ty.span,
+ msg,
|lint| {
- let mut diag = lint.build(msg);
- diag.multipart_suggestion_verbose(
+ lint.multipart_suggestion_verbose(
"use `dyn`",
sugg,
Applicability::MachineApplicable,
);
- self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
- diag.emit();
+ self.maybe_lint_blanket_trait_impl(&self_ty, lint);
+ lint
},
);
}
diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index 6a28bb16a..6a28bb16a 100644
--- a/compiler/rustc_typeck/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index d6fa74c87..b70ac0205 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1,8 +1,7 @@
use crate::check::intrinsicck::InlineAsmCtxt;
-use super::coercion::CoerceMany;
use super::compare_method::check_type_bounds;
-use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl};
+use super::compare_method::{compare_impl_method, compare_ty_impl};
use super::*;
use rustc_attr as attr;
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
@@ -10,10 +9,8 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
-use rustc_hir::lang_items::LangItem;
use rustc_hir::{ItemKind, Node, PathSegment};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
@@ -29,13 +26,12 @@ use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVE
use rustc_span::symbol::sym;
use rustc_span::{self, Span};
use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCtxt};
-use rustc_ty_utils::representability::{self, Representability};
use std::ops::ControlFlow;
-pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
+pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
match tcx.sess.target.is_abi_supported(abi) {
Some(true) => (),
Some(false) => {
@@ -48,9 +44,13 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab
.emit();
}
None => {
- tcx.struct_span_lint_hir(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
- lint.build("use of calling convention not supported on this target").emit();
- });
+ tcx.struct_span_lint_hir(
+ UNSUPPORTED_CALLING_CONVENTIONS,
+ hir_id,
+ span,
+ "use of calling convention not supported on this target",
+ |lint| lint,
+ );
}
}
@@ -66,318 +66,10 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab
}
}
-/// Helper used for fns and closures. Does the grungy work of checking a function
-/// body and returns the function context used for that purpose, since in the case of a fn item
-/// there is still a bit more to do.
-///
-/// * ...
-/// * inherited: other fields inherited from the enclosing fn (if any)
-#[instrument(skip(inherited, body), level = "debug")]
-pub(super) fn check_fn<'a, 'tcx>(
- inherited: &'a Inherited<'a, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- fn_sig: ty::FnSig<'tcx>,
- decl: &'tcx hir::FnDecl<'tcx>,
- fn_id: hir::HirId,
- body: &'tcx hir::Body<'tcx>,
- can_be_generator: Option<hir::Movability>,
- return_type_pre_known: bool,
-) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
- // Create the function context. This is either derived from scratch or,
- // in the case of closures, based on the outer context.
- let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
- fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
- fcx.return_type_pre_known = return_type_pre_known;
-
- let tcx = fcx.tcx;
- let hir = tcx.hir();
-
- let declared_ret_ty = fn_sig.output();
-
- let ret_ty =
- fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
- declared_ret_ty,
- body.value.hir_id,
- decl.output.span(),
- param_env,
- ));
- // If we replaced declared_ret_ty with infer vars, then we must be inferring
- // an opaque type, so set a flag so we can improve diagnostics.
- fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
-
- fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
-
- let span = body.value.span;
-
- fn_maybe_err(tcx, span, fn_sig.abi);
-
- if fn_sig.abi == Abi::RustCall {
- let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
-
- let err = || {
- let item = match tcx.hir().get(fn_id) {
- Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
- Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::Fn(header, ..), ..
- }) => Some(header),
- Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Fn(header, ..),
- ..
- }) => Some(header),
- // Closures are RustCall, but they tuple their arguments, so shouldn't be checked
- Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
- node => bug!("Item being checked wasn't a function/closure: {:?}", node),
- };
-
- if let Some(header) = item {
- tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
- }
- };
-
- if fn_sig.inputs().len() != expected_args {
- err()
- } else {
- // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
- // This will probably require wide-scale changes to support a TupleKind obligation
- // We can't resolve this without knowing the type of the param
- if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
- err()
- }
- }
- }
-
- if body.generator_kind.is_some() && can_be_generator.is_some() {
- let yield_ty = fcx
- .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
- fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
-
- // Resume type defaults to `()` if the generator has no argument.
- let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
-
- fcx.resume_yield_tys = Some((resume_ty, yield_ty));
- }
-
- GatherLocalsVisitor::new(&fcx).visit_body(body);
-
- // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
- // (as it's created inside the body itself, not passed in from outside).
- let maybe_va_list = if fn_sig.c_variadic {
- let span = body.params.last().unwrap().span;
- let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
- let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
-
- Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()]))
- } else {
- None
- };
-
- // Add formal parameters.
- let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
- let inputs_fn = fn_sig.inputs().iter().copied();
- for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
- // Check the pattern.
- let ty_span = try { inputs_hir?.get(idx)?.span };
- fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
-
- // Check that argument is Sized.
- // 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 {
- fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
- }
-
- fcx.write_ty(param.hir_id, param_ty);
- }
-
- inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
-
- fcx.in_tail_expr = true;
- if let ty::Dynamic(..) = declared_ret_ty.kind() {
- // FIXME: We need to verify that the return type is `Sized` after the return expression has
- // been evaluated so that we have types available for all the nodes being returned, but that
- // 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.in_tail_expr = false;
-
- // We insert the deferred_generator_interiors entry after visiting the body.
- // This ensures that all nested generators appear before the entry of this generator.
- // resolve_generator_interiors relies on this property.
- let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
- let interior = fcx
- .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
- fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
-
- let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
- Some(GeneratorTypes {
- resume_ty,
- yield_ty,
- interior,
- movability: can_be_generator.unwrap(),
- })
- } else {
- None
- };
-
- // Finalize the return check by taking the LUB of the return types
- // we saw and assigning it to the expected return type. This isn't
- // really expected to fail, since the coercions would have failed
- // earlier when trying to find a LUB.
- let coercion = fcx.ret_coercion.take().unwrap().into_inner();
- let mut actual_return_ty = coercion.complete(&fcx);
- debug!("actual_return_ty = {:?}", actual_return_ty);
- if let ty::Dynamic(..) = declared_ret_ty.kind() {
- // We have special-cased the case where the function is declared
- // `-> dyn Foo` and we don't actually relate it to the
- // `fcx.ret_coercion`, so just substitute a type variable.
- actual_return_ty =
- fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
- debug!("actual_return_ty replaced with {:?}", actual_return_ty);
- }
-
- // HACK(oli-obk, compiler-errors): We should be comparing this against
- // `declared_ret_ty`, but then anything uninferred would be inferred to
- // the opaque type itself. That again would cause writeback to assume
- // we have a recursive call site and do the sadly stabilized fallback to `()`.
- fcx.demand_suptype(span, ret_ty, actual_return_ty);
-
- // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
- if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
- && panic_impl_did == hir.local_def_id(fn_id).to_def_id()
- {
- check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
- }
-
- // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
- if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
- && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
- {
- check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
- }
-
- (fcx, gen_ty)
-}
-
-fn check_panic_info_fn(
- tcx: TyCtxt<'_>,
- fn_id: LocalDefId,
- fn_sig: ty::FnSig<'_>,
- decl: &hir::FnDecl<'_>,
- declared_ret_ty: Ty<'_>,
-) {
- let Some(panic_info_did) = tcx.lang_items().panic_info() else {
- tcx.sess.err("language item required, but not found: `panic_info`");
- return;
- };
-
- if *declared_ret_ty.kind() != ty::Never {
- tcx.sess.span_err(decl.output.span(), "return type should be `!`");
- }
-
- let inputs = fn_sig.inputs();
- if inputs.len() != 1 {
- tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
- return;
- }
-
- let arg_is_panic_info = match *inputs[0].kind() {
- ty::Ref(region, ty, mutbl) => match *ty.kind() {
- ty::Adt(ref adt, _) => {
- adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
- }
- _ => false,
- },
- _ => false,
- };
-
- if !arg_is_panic_info {
- tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
- }
-
- let DefKind::Fn = tcx.def_kind(fn_id) else {
- let span = tcx.def_span(fn_id);
- tcx.sess.span_err(span, "should be a function");
- return;
- };
-
- let generic_counts = tcx.generics_of(fn_id).own_counts();
- if generic_counts.types != 0 {
- let span = tcx.def_span(fn_id);
- tcx.sess.span_err(span, "should have no type parameters");
- }
- if generic_counts.consts != 0 {
- let span = tcx.def_span(fn_id);
- tcx.sess.span_err(span, "should have no const parameters");
- }
-}
-
-fn check_alloc_error_fn(
- tcx: TyCtxt<'_>,
- fn_id: LocalDefId,
- fn_sig: ty::FnSig<'_>,
- decl: &hir::FnDecl<'_>,
- declared_ret_ty: Ty<'_>,
-) {
- let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
- tcx.sess.err("language item required, but not found: `alloc_layout`");
- return;
- };
-
- if *declared_ret_ty.kind() != ty::Never {
- tcx.sess.span_err(decl.output.span(), "return type should be `!`");
- }
-
- let inputs = fn_sig.inputs();
- if inputs.len() != 1 {
- tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
- return;
- }
-
- let arg_is_alloc_layout = match inputs[0].kind() {
- ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
- _ => false,
- };
-
- if !arg_is_alloc_layout {
- tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
- }
-
- let DefKind::Fn = tcx.def_kind(fn_id) else {
- let span = tcx.def_span(fn_id);
- tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
- return;
- };
-
- let generic_counts = tcx.generics_of(fn_id).own_counts();
- if generic_counts.types != 0 {
- let span = tcx.def_span(fn_id);
- tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
- }
- if generic_counts.consts != 0 {
- let span = tcx.def_span(fn_id);
- tcx.sess
- .span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
- }
-}
-
fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id);
def.destructor(tcx); // force the destructor to be evaluated
- check_representable(tcx, span, def_id);
if def.repr().simd() {
check_simd(tcx, span, def_id);
@@ -391,7 +83,6 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id);
def.destructor(tcx); // force the destructor to be evaluated
- check_representable(tcx, span, def_id);
check_transparent(tcx, span, def);
check_union_fields(tcx, span, def_id);
check_packed(tcx, span, def);
@@ -423,7 +114,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
_ => {
// Fallback case: allow `ManuallyDrop` and things that are `Copy`.
ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop())
- || ty.is_copy_modulo_regions(tcx.at(span), param_env)
+ || ty.is_copy_modulo_regions(tcx, param_env)
}
}
}
@@ -510,10 +201,10 @@ fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
UNINHABITED_STATIC,
tcx.hir().local_def_id_to_hir_id(def_id),
span,
+ "static of uninhabited type",
|lint| {
- lint.build("static of uninhabited type")
+ lint
.note("uninhabited statics cannot be initialized, and any access would be an immediate error")
- .emit();
},
);
}
@@ -521,23 +212,33 @@ fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
/// projections that would result in "inheriting lifetimes".
-pub(super) fn check_opaque<'tcx>(
- tcx: TyCtxt<'tcx>,
- def_id: LocalDefId,
- substs: SubstsRef<'tcx>,
- origin: &hir::OpaqueTyOrigin,
-) {
- let span = tcx.def_span(def_id);
- check_opaque_for_inheriting_lifetimes(tcx, def_id, span);
- if tcx.type_of(def_id).references_error() {
+fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
+ let item = tcx.hir().item(id);
+ let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else {
+ tcx.sess.delay_span_bug(tcx.hir().span(id.hir_id()), "expected opaque item");
+ return;
+ };
+
+ // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
+ // `async-std` (and `pub async fn` in general).
+ // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it!
+ // See https://github.com/rust-lang/rust/issues/75100
+ if tcx.sess.opts.actually_rustdoc {
+ return;
+ }
+
+ let substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id());
+ let span = tcx.def_span(item.owner_id.def_id);
+
+ check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span);
+ if tcx.type_of(item.owner_id.def_id).references_error() {
return;
}
- if check_opaque_for_cycles(tcx, def_id, substs, span, origin).is_err() {
+ if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() {
return;
}
- check_opaque_meets_bounds(tcx, def_id, substs, span, origin);
+ check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin);
}
-
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
/// in "inheriting lifetimes".
#[instrument(level = "debug", skip(tcx, span))]
@@ -609,9 +310,12 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
match arg.kind {
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
- [PathSegment { res: Res::SelfTy { trait_: _, alias_to: impl_ref }, .. }] => {
- let impl_ty_name =
- impl_ref.map(|(def_id, _)| self.tcx.def_path_str(def_id));
+ [PathSegment { res: Res::SelfTyParam { .. }, .. }] => {
+ let impl_ty_name = None;
+ self.selftys.push((path.span, impl_ty_name));
+ }
+ [PathSegment { res: Res::SelfTyAlias { alias_to: def_id, .. }, .. }] => {
+ let impl_ty_name = Some(self.tcx.def_path_str(*def_id));
self.selftys.push((path.span, impl_ty_name));
}
_ => {}
@@ -701,10 +405,12 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
/// check those cases in the `param_env` of that function, which may have
/// bounds not on this opaque type:
///
-/// type X<T> = impl Clone
+/// ```ignore (illustrative)
+/// type X<T> = impl Clone;
/// fn f<T: Clone>(t: T) -> X<T> {
/// t
/// }
+/// ```
///
/// Without this check the above code is incorrectly accepted: we would ICE if
/// some tried, for example, to clone an `Option<X<&mut ()>>`.
@@ -716,8 +422,6 @@ fn check_opaque_meets_bounds<'tcx>(
span: Span,
origin: &hir::OpaqueTyOrigin,
) {
- let hidden_type = tcx.bound_type_of(def_id.to_def_id()).subst(tcx, substs);
-
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let defining_use_anchor = match *origin {
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
@@ -725,76 +429,88 @@ fn check_opaque_meets_bounds<'tcx>(
};
let param_env = tcx.param_env(defining_use_anchor);
- tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor)).enter(
- move |infcx| {
- let ocx = ObligationCtxt::new(&infcx);
- let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
+ let infcx = tcx
+ .infer_ctxt()
+ .with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor))
+ .build();
+ let ocx = ObligationCtxt::new(&infcx);
+ let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
+
+ // `ReErased` regions appear in the "parent_substs" of closures/generators.
+ // We're ignoring them here and replacing them with fresh region variables.
+ // See tests in ui/type-alias-impl-trait/closure_{parent_substs,wf_outlives}.rs.
+ //
+ // FIXME: Consider wrapping the hidden type in an existential `Binder` and instantiating it
+ // here rather than using ReErased.
+ let hidden_ty = tcx.bound_type_of(def_id.to_def_id()).subst(tcx, substs);
+ let hidden_ty = tcx.fold_regions(hidden_ty, |re, _dbi| match re.kind() {
+ ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)),
+ _ => re,
+ });
- let misc_cause = traits::ObligationCause::misc(span, hir_id);
+ let misc_cause = traits::ObligationCause::misc(span, hir_id);
- match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
- Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
- Err(ty_err) => {
- tcx.sess.delay_span_bug(
- span,
- &format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"),
- );
- }
- }
+ match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_ty) {
+ Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
+ Err(ty_err) => {
+ tcx.sess.delay_span_bug(
+ span,
+ &format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
+ );
+ }
+ }
- // Additionally require the hidden type to be well-formed with only the generics of the opaque type.
- // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
- // hidden type is well formed even without those bounds.
- let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into()))
- .to_predicate(tcx);
- ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
-
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- }
- match origin {
- // Checked when type checking the function containing them.
- hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
- // Can have different predicates to their defining use
- hir::OpaqueTyOrigin::TyAlias => {
- let outlives_environment = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(
- defining_use_anchor,
- &outlives_environment,
- );
- }
- }
- // Clean up after ourselves
- let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
- },
- );
+ // Additionally require the hidden type to be well-formed with only the generics of the opaque type.
+ // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
+ // hidden type is well formed even without those bounds.
+ let predicate =
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_ty.into())).to_predicate(tcx);
+ ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
+
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ }
+ match origin {
+ // Checked when type checking the function containing them.
+ hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
+ // Can have different predicates to their defining use
+ hir::OpaqueTyOrigin::TyAlias => {
+ let outlives_environment = OutlivesEnvironment::new(param_env);
+ infcx.check_region_obligations_and_report_errors(
+ defining_use_anchor,
+ &outlives_environment,
+ );
+ }
+ }
+ // Clean up after ourselves
+ let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
}
fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
debug!(
"check_item_type(it.def_id={:?}, it.name={})",
- id.def_id,
- tcx.def_path_str(id.def_id.to_def_id())
+ id.owner_id,
+ tcx.def_path_str(id.owner_id.to_def_id())
);
let _indenter = indenter();
- match tcx.def_kind(id.def_id) {
+ match tcx.def_kind(id.owner_id) {
DefKind::Static(..) => {
- tcx.ensure().typeck(id.def_id);
- maybe_check_static_with_link_section(tcx, id.def_id);
- check_static_inhabited(tcx, id.def_id);
+ tcx.ensure().typeck(id.owner_id.def_id);
+ maybe_check_static_with_link_section(tcx, id.owner_id.def_id);
+ check_static_inhabited(tcx, id.owner_id.def_id);
}
DefKind::Const => {
- tcx.ensure().typeck(id.def_id);
+ tcx.ensure().typeck(id.owner_id.def_id);
}
DefKind::Enum => {
let item = tcx.hir().item(id);
let hir::ItemKind::Enum(ref enum_definition, _) = item.kind else {
return;
};
- check_enum(tcx, &enum_definition.variants, item.def_id);
+ check_enum(tcx, &enum_definition.variants, item.owner_id.def_id);
}
DefKind::Fn => {} // entirely within check_item_body
DefKind::Impl => {
@@ -802,12 +518,12 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
let hir::ItemKind::Impl(ref impl_) = it.kind else {
return;
};
- debug!("ItemKind::Impl {} with id {:?}", it.ident, it.def_id);
- if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.def_id) {
+ debug!("ItemKind::Impl {} with id {:?}", it.ident, it.owner_id);
+ if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.owner_id) {
check_impl_items_against_trait(
tcx,
it.span,
- it.def_id,
+ it.owner_id.def_id,
impl_trait_ref,
&impl_.items,
);
@@ -829,15 +545,15 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
fn_maybe_err(tcx, item.ident.span, abi);
}
hir::TraitItemKind::Type(.., Some(default)) => {
- let assoc_item = tcx.associated_item(item.def_id);
+ let assoc_item = tcx.associated_item(item.owner_id);
let trait_substs =
- InternalSubsts::identity_for_item(tcx, it.def_id.to_def_id());
+ InternalSubsts::identity_for_item(tcx, it.owner_id.to_def_id());
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
tcx,
assoc_item,
assoc_item,
default.span,
- ty::TraitRef { def_id: it.def_id.to_def_id(), substs: trait_substs },
+ ty::TraitRef { def_id: it.owner_id.to_def_id(), substs: trait_substs },
);
}
_ => {}
@@ -845,28 +561,28 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
}
}
DefKind::Struct => {
- check_struct(tcx, id.def_id);
+ check_struct(tcx, id.owner_id.def_id);
}
DefKind::Union => {
- check_union(tcx, id.def_id);
+ check_union(tcx, id.owner_id.def_id);
}
DefKind::OpaqueTy => {
- let item = tcx.hir().item(id);
- let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else {
- return;
- };
- // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
- // `async-std` (and `pub async fn` in general).
- // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it!
- // See https://github.com/rust-lang/rust/issues/75100
- if !tcx.sess.opts.actually_rustdoc {
- let substs = InternalSubsts::identity_for_item(tcx, item.def_id.to_def_id());
- check_opaque(tcx, item.def_id, substs, &origin);
+ check_opaque(tcx, id);
+ }
+ DefKind::ImplTraitPlaceholder => {
+ let parent = tcx.impl_trait_in_trait_parent(id.owner_id.to_def_id());
+ // Only check the validity of this opaque type if the function has a default body
+ if let hir::Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
+ ..
+ }) = tcx.hir().get_by_def_id(parent.expect_local())
+ {
+ check_opaque(tcx, id);
}
}
DefKind::TyAlias => {
- let pty_ty = tcx.type_of(id.def_id);
- let generics = tcx.generics_of(id.def_id);
+ let pty_ty = tcx.type_of(id.owner_id);
+ let generics = tcx.generics_of(id.owner_id);
check_type_params_are_used(tcx, &generics, pty_ty);
}
DefKind::ForeignMod => {
@@ -888,7 +604,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
}
} else {
for item in items {
- let def_id = item.id.def_id;
+ let def_id = item.id.owner_id.def_id;
let generics = tcx.generics_of(def_id);
let own_counts = generics.own_counts();
if generics.params.len() - own_counts.lifetimes != 0 {
@@ -943,7 +659,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
// an error would be reported if this fails.
- let _ = traits::OnUnimplementedDirective::of_item(tcx, item.def_id.to_def_id());
+ let _ = traits::OnUnimplementedDirective::of_item(tcx, item.owner_id.to_def_id());
}
pub(super) fn check_specialization_validity<'tcx>(
@@ -1030,7 +746,7 @@ fn check_impl_items_against_trait<'tcx>(
let trait_def = tcx.trait_def(impl_trait_ref.def_id);
for impl_item in impl_item_refs {
- let ty_impl_item = tcx.associated_item(impl_item.id.def_id);
+ let ty_impl_item = tcx.associated_item(impl_item.id.owner_id);
let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id {
tcx.associated_item(trait_item_id)
} else {
@@ -1041,14 +757,10 @@ fn check_impl_items_against_trait<'tcx>(
let impl_item_full = tcx.hir().impl_item(impl_item.id);
match impl_item_full.kind {
hir::ImplItemKind::Const(..) => {
- // Find associated const definition.
- compare_const_impl(
- tcx,
- &ty_impl_item,
- impl_item.span,
- &ty_trait_item,
- impl_trait_ref,
- );
+ let _ = tcx.compare_assoc_const_impl_item_with_trait_item((
+ impl_item.id.owner_id.def_id,
+ ty_impl_item.trait_item_def_id.unwrap(),
+ ));
}
hir::ImplItemKind::Fn(..) => {
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
@@ -1060,7 +772,7 @@ fn check_impl_items_against_trait<'tcx>(
opt_trait_span,
);
}
- hir::ImplItemKind::TyAlias(impl_ty) => {
+ hir::ImplItemKind::Type(impl_ty) => {
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
compare_ty_impl(
tcx,
@@ -1148,27 +860,6 @@ fn check_impl_items_against_trait<'tcx>(
}
}
-/// Checks whether a type can be represented in memory. In particular, it
-/// identifies types that contain themselves without indirection through a
-/// pointer, which would mean their size is unbounded.
-pub(super) fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bool {
- let rty = tcx.type_of(item_def_id);
-
- // Check that it is possible to represent this type. This call identifies
- // (1) types that contain themselves and (2) types that contain a different
- // recursive type. It is only necessary to throw an error on those that
- // contain themselves. For case 2, there must be an inner type that will be
- // caught by case 1.
- match representability::ty_is_representable(tcx, rty, sp, None) {
- Representability::SelfRecursive(spans) => {
- recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans);
- return false;
- }
- Representability::Representable | Representability::ContainsRecursive => (),
- }
- true
-}
-
pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
let t = tcx.type_of(def_id);
if let ty::Adt(def, substs) = t.kind()
@@ -1434,6 +1125,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
span,
+ "zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types",
|lint| {
let note = if non_exhaustive {
"is marked with `#[non_exhaustive]`"
@@ -1441,10 +1133,9 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
"contains private fields"
};
let field_ty = tcx.def_path_str_with_substs(def_id, substs);
- lint.build("zero-sized fields in repr(transparent) cannot contain external non-exhaustive types")
+ lint
.note(format!("this {descr} contains `{field_ty}`, which {note}, \
and makes it not a breaking change to become non-zero-sized in the future."))
- .emit();
},
)
}
@@ -1489,7 +1180,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
}
}
- if tcx.adt_def(def_id).repr().int.is_none() && tcx.features().arbitrary_enum_discriminant {
+ if tcx.adt_def(def_id).repr().int.is_none() {
let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..));
let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
@@ -1506,7 +1197,6 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
- check_representable(tcx, sp, def_id);
check_transparent(tcx, sp, def);
}
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs
index 59d591acd..32f66b06f 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs
@@ -1,6 +1,6 @@
use super::potentially_plural_count;
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
-use hir::def_id::DefId;
+use hir::def_id::{DefId, LocalDefId};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
use rustc_hir as hir;
@@ -12,14 +12,14 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
use rustc_infer::infer::{self, TyCtxtInferExt};
use rustc_infer::traits::util;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
use rustc_middle::ty::util::ExplicitSelf;
+use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::{
self, AssocItem, DefIdTree, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
};
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
use rustc_span::Span;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::{
self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
@@ -215,224 +215,220 @@ fn compare_predicate_entailment<'tcx>(
);
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
- tcx.infer_ctxt().enter(|ref infcx| {
- let ocx = ObligationCtxt::new(infcx);
+ let infcx = &tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(infcx);
- debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
+ debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
- let mut selcx = traits::SelectionContext::new(&infcx);
- let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
- for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
- let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
- let traits::Normalized { value: predicate, obligations } =
- traits::normalize(&mut selcx, param_env, normalize_cause, predicate);
+ let mut selcx = traits::SelectionContext::new(&infcx);
+ let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
+ for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
+ let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
+ let traits::Normalized { value: predicate, obligations } =
+ traits::normalize(&mut selcx, param_env, normalize_cause, predicate);
- ocx.register_obligations(obligations);
- let cause = ObligationCause::new(
- span,
- impl_m_hir_id,
- ObligationCauseCode::CompareImplItemObligation {
- impl_item_def_id: impl_m.def_id.expect_local(),
- trait_item_def_id: trait_m.def_id,
- kind: impl_m.kind,
- },
- );
- ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
- }
-
- // We now need to check that the signature of the impl method is
- // compatible with that of the trait method. We do this by
- // checking that `impl_fty <: trait_fty`.
- //
- // FIXME. Unfortunately, this doesn't quite work right now because
- // associated type normalization is not integrated into subtype
- // checks. For the comparison to be valid, we need to
- // normalize the associated types in the impl/trait methods
- // first. However, because function types bind regions, just
- // calling `normalize_associated_types_in` would have no effect on
- // any associated types appearing in the fn arguments or return
- // type.
-
- // Compute placeholder form of impl and trait method tys.
- let tcx = infcx.tcx;
-
- let mut wf_tys = FxHashSet::default();
-
- let impl_sig = infcx.replace_bound_vars_with_fresh_vars(
- impl_m_span,
- infer::HigherRankedType,
- tcx.fn_sig(impl_m.def_id),
+ ocx.register_obligations(obligations);
+ let cause = ObligationCause::new(
+ span,
+ impl_m_hir_id,
+ ObligationCauseCode::CompareImplItemObligation {
+ impl_item_def_id: impl_m.def_id.expect_local(),
+ trait_item_def_id: trait_m.def_id,
+ kind: impl_m.kind,
+ },
);
+ ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
+ }
- let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id);
- let impl_sig = ocx.normalize(norm_cause.clone(), param_env, impl_sig);
- let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
- debug!("compare_impl_method: impl_fty={:?}", impl_fty);
-
- let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
- let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
-
- // Next, add all inputs and output as well-formed tys. Importantly,
- // we have to do this before normalization, since the normalized ty may
- // not contain the input parameters. See issue #87748.
- wf_tys.extend(trait_sig.inputs_and_output.iter());
- let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig);
- // We also have to add the normalized trait signature
- // as we don't normalize during implied bounds computation.
- wf_tys.extend(trait_sig.inputs_and_output.iter());
- let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
-
- debug!("compare_impl_method: trait_fty={:?}", trait_fty);
-
- // FIXME: We'd want to keep more accurate spans than "the method signature" when
- // processing the comparison between the trait and impl fn, but we sadly lose them
- // and point at the whole signature when a trait bound or specific input or output
- // type would be more appropriate. In other places we have a `Vec<Span>`
- // corresponding to their `Vec<Predicate>`, but we don't have that here.
- // Fixing this would improve the output of test `issue-83765.rs`.
- let mut result = infcx
- .at(&cause, param_env)
- .sup(trait_fty, impl_fty)
- .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok));
-
- // HACK(RPITIT): #101614. When we are trying to infer the hidden types for
- // RPITITs, we need to equate the output tys instead of just subtyping. If
- // we just use `sup` above, we'll end up `&'static str <: _#1t`, which causes
- // us to infer `_#1t = #'_#2r str`, where `'_#2r` is unconstrained, which gets
- // fixed up to `ReEmpty`, and which is certainly not what we want.
- if trait_fty.has_infer_types() {
- result = result.and_then(|()| {
- infcx
- .at(&cause, param_env)
- .eq(trait_sig.output(), impl_sig.output())
- .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok))
- });
- }
+ // We now need to check that the signature of the impl method is
+ // compatible with that of the trait method. We do this by
+ // checking that `impl_fty <: trait_fty`.
+ //
+ // FIXME. Unfortunately, this doesn't quite work right now because
+ // associated type normalization is not integrated into subtype
+ // checks. For the comparison to be valid, we need to
+ // normalize the associated types in the impl/trait methods
+ // first. However, because function types bind regions, just
+ // calling `normalize_associated_types_in` would have no effect on
+ // any associated types appearing in the fn arguments or return
+ // type.
+
+ // Compute placeholder form of impl and trait method tys.
+ let tcx = infcx.tcx;
- if let Err(terr) = result {
- debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
+ let mut wf_tys = FxHashSet::default();
- let (impl_err_span, trait_err_span) =
- extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
+ let impl_sig = infcx.replace_bound_vars_with_fresh_vars(
+ impl_m_span,
+ infer::HigherRankedType,
+ tcx.fn_sig(impl_m.def_id),
+ );
- cause.span = impl_err_span;
+ let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id);
+ let impl_sig = ocx.normalize(norm_cause.clone(), param_env, impl_sig);
+ let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
+ debug!("compare_impl_method: impl_fty={:?}", impl_fty);
+
+ let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
+ let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
+
+ // Next, add all inputs and output as well-formed tys. Importantly,
+ // we have to do this before normalization, since the normalized ty may
+ // not contain the input parameters. See issue #87748.
+ wf_tys.extend(trait_sig.inputs_and_output.iter());
+ let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig);
+ // We also have to add the normalized trait signature
+ // as we don't normalize during implied bounds computation.
+ wf_tys.extend(trait_sig.inputs_and_output.iter());
+ let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
+
+ debug!("compare_impl_method: trait_fty={:?}", trait_fty);
+
+ // FIXME: We'd want to keep more accurate spans than "the method signature" when
+ // processing the comparison between the trait and impl fn, but we sadly lose them
+ // and point at the whole signature when a trait bound or specific input or output
+ // type would be more appropriate. In other places we have a `Vec<Span>`
+ // corresponding to their `Vec<Predicate>`, but we don't have that here.
+ // Fixing this would improve the output of test `issue-83765.rs`.
+ let mut result = infcx
+ .at(&cause, param_env)
+ .sup(trait_fty, impl_fty)
+ .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok));
+
+ // HACK(RPITIT): #101614. When we are trying to infer the hidden types for
+ // RPITITs, we need to equate the output tys instead of just subtyping. If
+ // we just use `sup` above, we'll end up `&'static str <: _#1t`, which causes
+ // us to infer `_#1t = #'_#2r str`, where `'_#2r` is unconstrained, which gets
+ // fixed up to `ReEmpty`, and which is certainly not what we want.
+ if trait_fty.has_infer_types() {
+ result = result.and_then(|()| {
+ infcx
+ .at(&cause, param_env)
+ .eq(trait_sig.output(), impl_sig.output())
+ .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok))
+ });
+ }
- let mut diag = struct_span_err!(
- tcx.sess,
- cause.span(),
- E0053,
- "method `{}` has an incompatible type for trait",
- trait_m.name
- );
- match &terr {
- TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
- if trait_m.fn_has_self_parameter =>
- {
- let ty = trait_sig.inputs()[0];
- let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty())
- {
- ExplicitSelf::ByValue => "self".to_owned(),
- ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
- ExplicitSelf::ByReference(_, hir::Mutability::Mut) => {
- "&mut self".to_owned()
- }
- _ => format!("self: {ty}"),
- };
+ if let Err(terr) = result {
+ debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
- // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
- // span points only at the type `Box<Self`>, but we want to cover the whole
- // argument pattern and type.
- let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
- ImplItemKind::Fn(ref sig, body) => tcx
- .hir()
- .body_param_names(body)
- .zip(sig.decl.inputs.iter())
- .map(|(param, ty)| param.span.to(ty.span))
- .next()
- .unwrap_or(impl_err_span),
- _ => bug!("{:?} is not a method", impl_m),
- };
+ let (impl_err_span, trait_err_span) =
+ extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
+ cause.span = impl_err_span;
+
+ let mut diag = struct_span_err!(
+ tcx.sess,
+ cause.span(),
+ E0053,
+ "method `{}` has an incompatible type for trait",
+ trait_m.name
+ );
+ match &terr {
+ TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
+ if trait_m.fn_has_self_parameter =>
+ {
+ let ty = trait_sig.inputs()[0];
+ let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) {
+ ExplicitSelf::ByValue => "self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
+ _ => format!("self: {ty}"),
+ };
+
+ // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
+ // span points only at the type `Box<Self`>, but we want to cover the whole
+ // argument pattern and type.
+ let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+ ImplItemKind::Fn(ref sig, body) => tcx
+ .hir()
+ .body_param_names(body)
+ .zip(sig.decl.inputs.iter())
+ .map(|(param, ty)| param.span.to(ty.span))
+ .next()
+ .unwrap_or(impl_err_span),
+ _ => bug!("{:?} is not a method", impl_m),
+ };
+
+ diag.span_suggestion(
+ span,
+ "change the self-receiver type to match the trait",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+ TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
+ if trait_sig.inputs().len() == *i {
+ // Suggestion to change output type. We do not suggest in `async` functions
+ // to avoid complex logic or incorrect output.
+ match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+ ImplItemKind::Fn(ref sig, _)
+ if sig.header.asyncness == hir::IsAsync::NotAsync =>
+ {
+ let msg = "change the output type to match the trait";
+ let ap = Applicability::MachineApplicable;
+ match sig.decl.output {
+ hir::FnRetTy::DefaultReturn(sp) => {
+ let sugg = format!("-> {} ", trait_sig.output());
+ diag.span_suggestion_verbose(sp, msg, sugg, ap);
+ }
+ hir::FnRetTy::Return(hir_ty) => {
+ let sugg = trait_sig.output();
+ diag.span_suggestion(hir_ty.span, msg, sugg, ap);
+ }
+ };
+ }
+ _ => {}
+ };
+ } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
diag.span_suggestion(
- span,
- "change the self-receiver type to match the trait",
- sugg,
+ impl_err_span,
+ "change the parameter type to match the trait",
+ trait_ty,
Applicability::MachineApplicable,
);
}
- TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
- if trait_sig.inputs().len() == *i {
- // Suggestion to change output type. We do not suggest in `async` functions
- // to avoid complex logic or incorrect output.
- match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
- ImplItemKind::Fn(ref sig, _)
- if sig.header.asyncness == hir::IsAsync::NotAsync =>
- {
- let msg = "change the output type to match the trait";
- let ap = Applicability::MachineApplicable;
- match sig.decl.output {
- hir::FnRetTy::DefaultReturn(sp) => {
- let sugg = format!("-> {} ", trait_sig.output());
- diag.span_suggestion_verbose(sp, msg, sugg, ap);
- }
- hir::FnRetTy::Return(hir_ty) => {
- let sugg = trait_sig.output();
- diag.span_suggestion(hir_ty.span, msg, sugg, ap);
- }
- };
- }
- _ => {}
- };
- } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
- diag.span_suggestion(
- impl_err_span,
- "change the parameter type to match the trait",
- trait_ty,
- Applicability::MachineApplicable,
- );
- }
- }
- _ => {}
}
+ _ => {}
+ }
- infcx.note_type_err(
- &mut diag,
- &cause,
- trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
- Some(infer::ValuePairs::Terms(ExpectedFound {
- expected: trait_fty.into(),
- found: impl_fty.into(),
- })),
- terr,
- false,
- false,
- );
+ infcx.err_ctxt().note_type_err(
+ &mut diag,
+ &cause,
+ trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
+ Some(infer::ValuePairs::Terms(ExpectedFound {
+ expected: trait_fty.into(),
+ found: impl_fty.into(),
+ })),
+ terr,
+ false,
+ false,
+ );
- return Err(diag.emit());
- }
+ return Err(diag.emit());
+ }
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- let reported = infcx.report_fulfillment_errors(&errors, None, false);
- return Err(reported);
- }
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ return Err(reported);
+ }
- // Finally, resolve all regions. This catches wily misuses of
- // lifetime parameters.
- let outlives_environment = OutlivesEnvironment::with_bounds(
- param_env,
- Some(infcx),
- infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
- );
- infcx.check_region_obligations_and_report_errors(
- impl_m.def_id.expect_local(),
- &outlives_environment,
- );
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters.
+ let outlives_environment = OutlivesEnvironment::with_bounds(
+ param_env,
+ Some(infcx),
+ infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
+ );
+ infcx.check_region_obligations_and_report_errors(
+ impl_m.def_id.expect_local(),
+ &outlives_environment,
+ );
- Ok(())
- })
+ Ok(())
}
pub fn collect_trait_impl_trait_tys<'tcx>(
@@ -465,125 +461,173 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
let trait_to_placeholder_substs =
impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
- tcx.infer_ctxt().enter(|ref infcx| {
- let ocx = ObligationCtxt::new(infcx);
+ let infcx = &tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(infcx);
- let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id);
- let impl_return_ty = ocx.normalize(
- norm_cause.clone(),
- param_env,
- infcx
- .replace_bound_vars_with_fresh_vars(
- return_span,
- infer::HigherRankedType,
- tcx.fn_sig(impl_m.def_id),
- )
- .output(),
- );
+ let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id);
+ let impl_sig = ocx.normalize(
+ norm_cause.clone(),
+ param_env,
+ infcx.replace_bound_vars_with_fresh_vars(
+ return_span,
+ infer::HigherRankedType,
+ tcx.fn_sig(impl_m.def_id),
+ ),
+ );
+ let impl_return_ty = impl_sig.output();
- let mut collector =
- ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
- let unnormalized_trait_return_ty = tcx
- .liberate_late_bound_regions(
- impl_m.def_id,
- tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
- )
- .output()
- .fold_with(&mut collector);
- let trait_return_ty =
- ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_return_ty);
+ let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
+ let unnormalized_trait_sig = tcx
+ .liberate_late_bound_regions(
+ impl_m.def_id,
+ tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
+ )
+ .fold_with(&mut collector);
+ let trait_sig = ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_sig);
+ let trait_return_ty = trait_sig.output();
- let wf_tys = FxHashSet::from_iter([unnormalized_trait_return_ty, trait_return_ty]);
+ let wf_tys = FxHashSet::from_iter(
+ unnormalized_trait_sig.inputs_and_output.iter().chain(trait_sig.inputs_and_output.iter()),
+ );
- match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) {
- Ok(infer::InferOk { value: (), obligations }) => {
- ocx.register_obligations(obligations);
- }
- Err(terr) => {
- let mut diag = struct_span_err!(
- tcx.sess,
- cause.span(),
- E0053,
- "method `{}` has an incompatible return type for trait",
- trait_m.name
- );
- let hir = tcx.hir();
- infcx.note_type_err(
- &mut diag,
- &cause,
- hir.get_if_local(impl_m.def_id)
- .and_then(|node| node.fn_decl())
- .map(|decl| (decl.output.span(), "return type in trait".to_owned())),
- Some(infer::ValuePairs::Terms(ExpectedFound {
- expected: trait_return_ty.into(),
- found: impl_return_ty.into(),
- })),
- terr,
- false,
- false,
- );
- return Err(diag.emit());
- }
+ match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) {
+ Ok(infer::InferOk { value: (), obligations }) => {
+ ocx.register_obligations(obligations);
}
+ Err(terr) => {
+ let mut diag = struct_span_err!(
+ tcx.sess,
+ cause.span(),
+ E0053,
+ "method `{}` has an incompatible return type for trait",
+ trait_m.name
+ );
+ let hir = tcx.hir();
+ infcx.err_ctxt().note_type_err(
+ &mut diag,
+ &cause,
+ hir.get_if_local(impl_m.def_id)
+ .and_then(|node| node.fn_decl())
+ .map(|decl| (decl.output.span(), "return type in trait".to_owned())),
+ Some(infer::ValuePairs::Terms(ExpectedFound {
+ expected: trait_return_ty.into(),
+ found: impl_return_ty.into(),
+ })),
+ terr,
+ false,
+ false,
+ );
+ return Err(diag.emit());
+ }
+ }
- // Check that all obligations are satisfied by the implementation's
- // RPITs.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- let reported = infcx.report_fulfillment_errors(&errors, None, false);
- return Err(reported);
+ // Unify the whole function signature. We need to do this to fully infer
+ // the lifetimes of the return type, but do this after unifying just the
+ // return types, since we want to avoid duplicating errors from
+ // `compare_predicate_entailment`.
+ match infcx
+ .at(&cause, param_env)
+ .eq(tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)), tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig)))
+ {
+ Ok(infer::InferOk { value: (), obligations }) => {
+ ocx.register_obligations(obligations);
}
+ Err(terr) => {
+ let guar = tcx.sess.delay_span_bug(
+ return_span,
+ format!("could not unify `{trait_sig}` and `{impl_sig}`: {terr:?}"),
+ );
+ return Err(guar);
+ }
+ }
- // Finally, resolve all regions. This catches wily misuses of
- // lifetime parameters.
- let outlives_environment = OutlivesEnvironment::with_bounds(
- param_env,
- Some(infcx),
- infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
- );
- infcx.check_region_obligations_and_report_errors(
- impl_m.def_id.expect_local(),
- &outlives_environment,
- );
+ // Check that all obligations are satisfied by the implementation's
+ // RPITs.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ return Err(reported);
+ }
- let mut collected_tys = FxHashMap::default();
- for (def_id, (ty, substs)) in collector.types {
- match infcx.fully_resolve(ty) {
- Ok(ty) => {
- // `ty` contains free regions that we created earlier while liberating the
- // trait fn signature. However, projection normalization expects `ty` to
- // contains `def_id`'s early-bound regions.
- let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
- debug!(?id_substs, ?substs);
- let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> = substs
- .iter()
- .enumerate()
- .map(|(index, arg)| (arg, id_substs[index]))
- .collect();
- debug!(?map);
-
- let ty = tcx.fold_regions(ty, |region, _| {
- if let ty::ReFree(_) = region.kind() {
- map[&region.into()].expect_region()
- } else {
- region
- }
- });
- debug!(%ty);
- collected_tys.insert(def_id, ty);
- }
- Err(err) => {
- tcx.sess.delay_span_bug(
- return_span,
- format!("could not fully resolve: {ty} => {err:?}"),
- );
- collected_tys.insert(def_id, tcx.ty_error());
- }
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters.
+ let outlives_environment = OutlivesEnvironment::with_bounds(
+ param_env,
+ Some(infcx),
+ infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
+ );
+ infcx.check_region_obligations_and_report_errors(
+ impl_m.def_id.expect_local(),
+ &outlives_environment,
+ );
+
+ let mut collected_tys = FxHashMap::default();
+ for (def_id, (ty, substs)) in collector.types {
+ match infcx.fully_resolve(ty) {
+ Ok(ty) => {
+ // `ty` contains free regions that we created earlier while liberating the
+ // trait fn signature. However, projection normalization expects `ty` to
+ // contains `def_id`'s early-bound regions.
+ let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
+ debug!(?id_substs, ?substs);
+ let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> =
+ std::iter::zip(substs, id_substs).collect();
+ debug!(?map);
+
+ // NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound
+ // region substs that are synthesized during AST lowering. These are substs
+ // that are appended to the parent substs (trait and trait method). However,
+ // we're trying to infer the unsubstituted type value of the RPITIT inside
+ // the *impl*, so we can later use the impl's method substs to normalize
+ // an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`).
+ //
+ // Due to the design of RPITITs, during AST lowering, we have no idea that
+ // an impl method corresponds to a trait method with RPITITs in it. Therefore,
+ // we don't have a list of early-bound region substs for the RPITIT in the impl.
+ // Since early region parameters are index-based, we can't just rebase these
+ // (trait method) early-bound region substs onto the impl, and there's no
+ // guarantee that the indices from the trait substs and impl substs line up.
+ // So to fix this, we subtract the number of trait substs and add the number of
+ // impl substs to *renumber* these early-bound regions to their corresponding
+ // indices in the impl's substitutions list.
+ //
+ // Also, we only need to account for a difference in trait and impl substs,
+ // since we previously enforce that the trait method and impl method have the
+ // same generics.
+ let num_trait_substs = trait_to_impl_substs.len();
+ let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len();
+ let ty = tcx.fold_regions(ty, |region, _| {
+ let (ty::ReFree(_) | ty::ReEarlyBound(_)) = region.kind() else { return region; };
+ let Some(ty::ReEarlyBound(e)) = map.get(&region.into()).map(|r| r.expect_region().kind())
+ else {
+ tcx
+ .sess
+ .delay_span_bug(
+ return_span,
+ "expected ReFree to map to ReEarlyBound"
+ );
+ return tcx.lifetimes.re_static;
+ };
+ tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
+ def_id: e.def_id,
+ name: e.name,
+ index: (e.index as usize - num_trait_substs + num_impl_substs) as u32,
+ }))
+ });
+ debug!(%ty);
+ collected_tys.insert(def_id, ty);
+ }
+ Err(err) => {
+ tcx.sess.delay_span_bug(
+ return_span,
+ format!("could not fully resolve: {ty} => {err:?}"),
+ );
+ collected_tys.insert(def_id, tcx.ty_error());
}
}
+ }
- Ok(&*tcx.arena.alloc(collected_tys))
- })
+ Ok(&*tcx.arena.alloc(collected_tys))
}
struct ImplTraitInTraitCollector<'a, 'tcx> {
@@ -628,10 +672,7 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
});
self.types.insert(proj.item_def_id, (infer_ty, proj.substs));
// Recurse into bounds
- for pred in self.tcx().bound_explicit_item_bounds(proj.item_def_id).transpose_iter() {
- let pred_span = pred.0.1;
-
- let pred = pred.map_bound(|(pred, _)| *pred).subst(self.tcx(), proj.substs);
+ for (pred, pred_span) in self.tcx().bound_explicit_item_bounds(proj.item_def_id).subst_iter_copied(self.tcx(), proj.substs) {
let pred = pred.fold_with(self);
let pred = self.ocx.normalize(
ObligationCause::misc(self.span, self.body_id),
@@ -712,8 +753,8 @@ fn check_region_bounds_on_impl_item<'tcx>(
}
#[instrument(level = "debug", skip(infcx))]
-fn extract_spans_for_error_reporting<'a, 'tcx>(
- infcx: &infer::InferCtxt<'a, 'tcx>,
+fn extract_spans_for_error_reporting<'tcx>(
+ infcx: &infer::InferCtxt<'tcx>,
terr: TypeError<'_>,
cause: &ObligationCause<'tcx>,
impl_m: &ty::AssocItem,
@@ -768,16 +809,15 @@ fn compare_self_type<'tcx>(
let self_arg_ty = tcx.fn_sig(method.def_id).input(0);
let param_env = ty::ParamEnv::reveal_all();
- tcx.infer_ctxt().enter(|infcx| {
- let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);
- let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok();
- match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
- ExplicitSelf::ByValue => "self".to_owned(),
- ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
- ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
- _ => format!("self: {self_arg_ty}"),
- }
- })
+ let infcx = tcx.infer_ctxt().build();
+ let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);
+ let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok();
+ match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
+ ExplicitSelf::ByValue => "self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
+ _ => format!("self: {self_arg_ty}"),
+ }
};
match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) {
@@ -1300,114 +1340,114 @@ fn compare_generic_param_kinds<'tcx>(
Ok(())
}
-pub(crate) fn compare_const_impl<'tcx>(
+/// Use `tcx.compare_assoc_const_impl_item_with_trait_item` instead
+pub(crate) fn raw_compare_const_impl<'tcx>(
tcx: TyCtxt<'tcx>,
- impl_c: &ty::AssocItem,
- impl_c_span: Span,
- trait_c: &ty::AssocItem,
- impl_trait_ref: ty::TraitRef<'tcx>,
-) {
+ (impl_const_item_def, trait_const_item_def): (LocalDefId, DefId),
+) -> Result<(), ErrorGuaranteed> {
+ let impl_const_item = tcx.associated_item(impl_const_item_def);
+ let trait_const_item = tcx.associated_item(trait_const_item_def);
+ let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap();
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
- tcx.infer_ctxt().enter(|infcx| {
- let param_env = tcx.param_env(impl_c.def_id);
- let ocx = ObligationCtxt::new(&infcx);
-
- // The below is for the most part highly similar to the procedure
- // for methods above. It is simpler in many respects, especially
- // because we shouldn't really have to deal with lifetimes or
- // predicates. In fact some of this should probably be put into
- // shared functions because of DRY violations...
- let trait_to_impl_substs = impl_trait_ref.substs;
-
- // Create a parameter environment that represents the implementation's
- // method.
- let impl_c_hir_id = tcx.hir().local_def_id_to_hir_id(impl_c.def_id.expect_local());
-
- // Compute placeholder form of impl and trait const tys.
- let impl_ty = tcx.type_of(impl_c.def_id);
- let trait_ty = tcx.bound_type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs);
- let mut cause = ObligationCause::new(
- impl_c_span,
- impl_c_hir_id,
- ObligationCauseCode::CompareImplItemObligation {
- impl_item_def_id: impl_c.def_id.expect_local(),
- trait_item_def_id: trait_c.def_id,
- kind: impl_c.kind,
- },
- );
+ let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id());
- // There is no "body" here, so just pass dummy id.
- let impl_ty = ocx.normalize(cause.clone(), param_env, impl_ty);
+ let infcx = tcx.infer_ctxt().build();
+ let param_env = tcx.param_env(impl_const_item_def.to_def_id());
+ let ocx = ObligationCtxt::new(&infcx);
- debug!("compare_const_impl: impl_ty={:?}", impl_ty);
+ // The below is for the most part highly similar to the procedure
+ // for methods above. It is simpler in many respects, especially
+ // because we shouldn't really have to deal with lifetimes or
+ // predicates. In fact some of this should probably be put into
+ // shared functions because of DRY violations...
+ let trait_to_impl_substs = impl_trait_ref.substs;
- let trait_ty = ocx.normalize(cause.clone(), param_env, trait_ty);
+ // Create a parameter environment that represents the implementation's
+ // method.
+ let impl_c_hir_id = tcx.hir().local_def_id_to_hir_id(impl_const_item_def);
- debug!("compare_const_impl: trait_ty={:?}", trait_ty);
+ // Compute placeholder form of impl and trait const tys.
+ let impl_ty = tcx.type_of(impl_const_item_def.to_def_id());
+ let trait_ty = tcx.bound_type_of(trait_const_item_def).subst(tcx, trait_to_impl_substs);
+ let mut cause = ObligationCause::new(
+ impl_c_span,
+ impl_c_hir_id,
+ ObligationCauseCode::CompareImplItemObligation {
+ impl_item_def_id: impl_const_item_def,
+ trait_item_def_id: trait_const_item_def,
+ kind: impl_const_item.kind,
+ },
+ );
- let err = infcx
- .at(&cause, param_env)
- .sup(trait_ty, impl_ty)
- .map(|ok| ocx.register_infer_ok_obligations(ok));
+ // There is no "body" here, so just pass dummy id.
+ let impl_ty = ocx.normalize(cause.clone(), param_env, impl_ty);
- if let Err(terr) = err {
- debug!(
- "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
- impl_ty, trait_ty
- );
+ debug!("compare_const_impl: impl_ty={:?}", impl_ty);
- // Locate the Span containing just the type of the offending impl
- match tcx.hir().expect_impl_item(impl_c.def_id.expect_local()).kind {
- ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
- _ => bug!("{:?} is not a impl const", impl_c),
- }
+ let trait_ty = ocx.normalize(cause.clone(), param_env, trait_ty);
- let mut diag = struct_span_err!(
- tcx.sess,
- cause.span,
- E0326,
- "implemented const `{}` has an incompatible type for trait",
- trait_c.name
- );
+ debug!("compare_const_impl: trait_ty={:?}", trait_ty);
- let trait_c_span = trait_c.def_id.as_local().map(|trait_c_def_id| {
- // Add a label to the Span containing just the type of the const
- match tcx.hir().expect_trait_item(trait_c_def_id).kind {
- TraitItemKind::Const(ref ty, _) => ty.span,
- _ => bug!("{:?} is not a trait const", trait_c),
- }
- });
+ let err = infcx
+ .at(&cause, param_env)
+ .sup(trait_ty, impl_ty)
+ .map(|ok| ocx.register_infer_ok_obligations(ok));
- infcx.note_type_err(
- &mut diag,
- &cause,
- trait_c_span.map(|span| (span, "type in trait".to_owned())),
- Some(infer::ValuePairs::Terms(ExpectedFound {
- expected: trait_ty.into(),
- found: impl_ty.into(),
- })),
- terr,
- false,
- false,
- );
- diag.emit();
- }
+ if let Err(terr) = err {
+ debug!(
+ "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
+ impl_ty, trait_ty
+ );
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- return;
+ // Locate the Span containing just the type of the offending impl
+ match tcx.hir().expect_impl_item(impl_const_item_def).kind {
+ ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
+ _ => bug!("{:?} is not a impl const", impl_const_item),
}
- let outlives_environment = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(
- impl_c.def_id.expect_local(),
- &outlives_environment,
+ let mut diag = struct_span_err!(
+ tcx.sess,
+ cause.span,
+ E0326,
+ "implemented const `{}` has an incompatible type for trait",
+ trait_const_item.name
);
- });
+
+ let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| {
+ // Add a label to the Span containing just the type of the const
+ match tcx.hir().expect_trait_item(trait_c_def_id).kind {
+ TraitItemKind::Const(ref ty, _) => ty.span,
+ _ => bug!("{:?} is not a trait const", trait_const_item),
+ }
+ });
+
+ infcx.err_ctxt().note_type_err(
+ &mut diag,
+ &cause,
+ trait_c_span.map(|span| (span, "type in trait".to_owned())),
+ Some(infer::ValuePairs::Terms(ExpectedFound {
+ expected: trait_ty.into(),
+ found: impl_ty.into(),
+ })),
+ terr,
+ false,
+ false,
+ );
+ return Err(diag.emit());
+ };
+
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None, false));
+ }
+
+ // FIXME return `ErrorReported` if region obligations error?
+ let outlives_environment = OutlivesEnvironment::new(param_env);
+ infcx.check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment);
+ Ok(())
}
pub(crate) fn compare_ty_impl<'tcx>(
@@ -1488,52 +1528,50 @@ fn compare_type_predicate_entailment<'tcx>(
hir::Constness::NotConst,
);
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
- tcx.infer_ctxt().enter(|infcx| {
- let ocx = ObligationCtxt::new(&infcx);
+ let infcx = tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(&infcx);
- debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
+ debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
- let mut selcx = traits::SelectionContext::new(&infcx);
-
- assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
- for (span, predicate) in
- std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
- {
- let cause = ObligationCause::misc(span, impl_ty_hir_id);
- let traits::Normalized { value: predicate, obligations } =
- traits::normalize(&mut selcx, param_env, cause, predicate);
-
- let cause = ObligationCause::new(
- span,
- impl_ty_hir_id,
- ObligationCauseCode::CompareImplItemObligation {
- impl_item_def_id: impl_ty.def_id.expect_local(),
- trait_item_def_id: trait_ty.def_id,
- kind: impl_ty.kind,
- },
- );
- ocx.register_obligations(obligations);
- ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
- }
+ let mut selcx = traits::SelectionContext::new(&infcx);
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- let reported = infcx.report_fulfillment_errors(&errors, None, false);
- return Err(reported);
- }
+ assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
+ for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
+ {
+ let cause = ObligationCause::misc(span, impl_ty_hir_id);
+ let traits::Normalized { value: predicate, obligations } =
+ traits::normalize(&mut selcx, param_env, cause, predicate);
- // Finally, resolve all regions. This catches wily misuses of
- // lifetime parameters.
- let outlives_environment = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(
- impl_ty.def_id.expect_local(),
- &outlives_environment,
+ let cause = ObligationCause::new(
+ span,
+ impl_ty_hir_id,
+ ObligationCauseCode::CompareImplItemObligation {
+ impl_item_def_id: impl_ty.def_id.expect_local(),
+ trait_item_def_id: trait_ty.def_id,
+ kind: impl_ty.kind,
+ },
);
+ ocx.register_obligations(obligations);
+ ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
+ }
+
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ return Err(reported);
+ }
+
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters.
+ let outlives_environment = OutlivesEnvironment::new(param_env);
+ infcx.check_region_obligations_and_report_errors(
+ impl_ty.def_id.expect_local(),
+ &outlives_environment,
+ );
- Ok(())
- })
+ Ok(())
}
/// Validate that `ProjectionCandidate`s created for this associated type will
@@ -1693,94 +1731,89 @@ pub fn check_type_bounds<'tcx>(
let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
- tcx.infer_ctxt().enter(move |infcx| {
- let ocx = ObligationCtxt::new(&infcx);
+ let infcx = tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(&infcx);
- let assumed_wf_types =
- ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local());
+ let assumed_wf_types =
+ ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local());
- let mut selcx = traits::SelectionContext::new(&infcx);
- let normalize_cause = ObligationCause::new(
- impl_ty_span,
- impl_ty_hir_id,
- ObligationCauseCode::CheckAssociatedTypeBounds {
- impl_item_def_id: impl_ty.def_id.expect_local(),
- trait_item_def_id: trait_ty.def_id,
- },
- );
- let mk_cause = |span: Span| {
- let code = if span.is_dummy() {
- traits::ItemObligation(trait_ty.def_id)
- } else {
- traits::BindingObligation(trait_ty.def_id, span)
- };
- ObligationCause::new(impl_ty_span, impl_ty_hir_id, code)
+ let mut selcx = traits::SelectionContext::new(&infcx);
+ let normalize_cause = ObligationCause::new(
+ impl_ty_span,
+ impl_ty_hir_id,
+ ObligationCauseCode::CheckAssociatedTypeBounds {
+ impl_item_def_id: impl_ty.def_id.expect_local(),
+ trait_item_def_id: trait_ty.def_id,
+ },
+ );
+ let mk_cause = |span: Span| {
+ let code = if span.is_dummy() {
+ traits::ItemObligation(trait_ty.def_id)
+ } else {
+ traits::BindingObligation(trait_ty.def_id, span)
};
+ ObligationCause::new(impl_ty_span, impl_ty_hir_id, code)
+ };
- let obligations = tcx
- .bound_explicit_item_bounds(trait_ty.def_id)
- .transpose_iter()
- .map(|e| e.map_bound(|e| *e).transpose_tuple2())
- .map(|(bound, span)| {
- debug!(?bound);
- // this is where opaque type is found
- let concrete_ty_bound = bound.subst(tcx, rebased_substs);
- debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
-
- traits::Obligation::new(mk_cause(span.0), param_env, concrete_ty_bound)
- })
- .collect();
- debug!("check_type_bounds: item_bounds={:?}", obligations);
-
- for mut obligation in util::elaborate_obligations(tcx, obligations) {
- let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
- &mut selcx,
- normalize_param_env,
- normalize_cause.clone(),
- obligation.predicate,
- );
- debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
- obligation.predicate = normalized_predicate;
+ let obligations = tcx
+ .bound_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);
+ traits::Obligation::new(mk_cause(span), param_env, concrete_ty_bound)
+ })
+ .collect();
+ debug!("check_type_bounds: item_bounds={:?}", obligations);
+
+ for mut obligation in util::elaborate_obligations(tcx, obligations) {
+ let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
+ &mut selcx,
+ normalize_param_env,
+ normalize_cause.clone(),
+ obligation.predicate,
+ );
+ debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
+ obligation.predicate = normalized_predicate;
- ocx.register_obligations(obligations);
- ocx.register_obligation(obligation);
- }
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- let reported = infcx.report_fulfillment_errors(&errors, None, false);
- return Err(reported);
- }
+ ocx.register_obligations(obligations);
+ ocx.register_obligation(obligation);
+ }
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ return Err(reported);
+ }
- // Finally, resolve all regions. This catches wily misuses of
- // lifetime parameters.
- let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_hir_id, assumed_wf_types);
- let outlives_environment =
- OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds);
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters.
+ let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_hir_id, assumed_wf_types);
+ let outlives_environment =
+ OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds);
- infcx.check_region_obligations_and_report_errors(
- impl_ty.def_id.expect_local(),
- &outlives_environment,
- );
+ infcx.check_region_obligations_and_report_errors(
+ impl_ty.def_id.expect_local(),
+ &outlives_environment,
+ );
- let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
- for (key, value) in constraints {
- infcx
- .report_mismatched_types(
- &ObligationCause::misc(
- value.hidden_type.span,
- tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()),
- ),
- tcx.mk_opaque(key.def_id.to_def_id(), key.substs),
- value.hidden_type.ty,
- TypeError::Mismatch,
- )
- .emit();
- }
+ let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+ for (key, value) in constraints {
+ infcx
+ .err_ctxt()
+ .report_mismatched_types(
+ &ObligationCause::misc(
+ value.hidden_type.span,
+ tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()),
+ ),
+ tcx.mk_opaque(key.def_id.to_def_id(), key.substs),
+ value.hidden_type.ty,
+ TypeError::Mismatch,
+ )
+ .emit();
+ }
- Ok(())
- })
+ Ok(())
}
fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index ab143c059..a74016e22 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -1,4 +1,4 @@
-// FIXME(@lcnr): Move this module out of `rustc_typeck`.
+// 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};
@@ -184,13 +184,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
let p = p.kind();
match (predicate.skip_binder(), p.skip_binder()) {
(ty::PredicateKind::Trait(a), ty::PredicateKind::Trait(b)) => {
- // Since struct predicates cannot have ~const, project the impl predicate
- // onto one that ignores the constness. This is equivalent to saying that
- // we match a `Trait` bound on the struct with a `Trait` or `~const Trait`
- // in the impl.
- let non_const_a =
- ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..a };
- relator.relate(predicate.rebind(non_const_a), p.rebind(b)).is_ok()
+ relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
}
(ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => {
relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
@@ -198,7 +192,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
(
ty::PredicateKind::ConstEvaluatable(a),
ty::PredicateKind::ConstEvaluatable(b),
- ) => tcx.try_unify_abstract_consts(self_param_env.and((a, b))),
+ ) => relator.relate(predicate.rebind(a), predicate.rebind(b)).is_ok(),
(
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)),
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)),
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index c7425ff78..609095c9c 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -7,10 +7,10 @@ use crate::errors::{
};
use crate::require_same_types;
-use rustc_errors::struct_span_err;
+use hir::def_id::DefId;
+use rustc_errors::{struct_span_err, DiagnosticMessage};
use rustc_hir as hir;
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
-use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_target::spec::abi::Abi;
@@ -26,7 +26,7 @@ fn equate_intrinsic_type<'tcx>(
) {
let (own_counts, span) = match &it.kind {
hir::ForeignItemKind::Fn(.., generics) => {
- let own_counts = tcx.generics_of(it.def_id.to_def_id()).own_counts();
+ let own_counts = tcx.generics_of(it.owner_id.to_def_id()).own_counts();
(own_counts, generics.span)
}
_ => {
@@ -57,13 +57,17 @@ fn equate_intrinsic_type<'tcx>(
{
let fty = tcx.mk_fn_ptr(sig);
let cause = ObligationCause::new(it.span, it.hir_id(), ObligationCauseCode::IntrinsicType);
- require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.def_id)), fty);
+ require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id)), fty);
}
}
/// Returns the unsafety of the given intrinsic.
-pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
- match intrinsic {
+pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir::Unsafety {
+ let has_safe_attr = match tcx.has_attr(intrinsic_id, sym::rustc_safe_intrinsic) {
+ true => hir::Unsafety::Normal,
+ false => hir::Unsafety::Unsafe,
+ };
+ let is_in_list = match tcx.item_name(intrinsic_id) {
// When adding a new intrinsic to this list,
// it's usually worth updating that intrinsic's documentation
// to note that it's safe to call, since
@@ -107,14 +111,26 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
| sym::variant_count
| sym::ptr_mask => hir::Unsafety::Normal,
_ => hir::Unsafety::Unsafe,
+ };
+
+ if has_safe_attr != is_in_list {
+ tcx.sess.struct_span_err(
+ tcx.def_span(intrinsic_id),
+ DiagnosticMessage::Str(format!(
+ "intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `{}`",
+ tcx.item_name(intrinsic_id)
+ ))).emit();
}
+
+ is_in_list
}
/// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`,
/// and in `library/core/src/intrinsics.rs`.
pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)));
- let intrinsic_name = tcx.item_name(it.def_id.to_def_id());
+ let intrinsic_id = it.owner_id.to_def_id();
+ let intrinsic_name = tcx.item_name(intrinsic_id);
let name_str = intrinsic_name.as_str();
let bound_vars = tcx.mk_bound_variable_kinds(
@@ -161,7 +177,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
};
(n_tps, 0, inputs, output, hir::Unsafety::Unsafe)
} else {
- let unsafety = intrinsic_operation_unsafety(intrinsic_name);
+ let unsafety = intrinsic_operation_unsafety(tcx, intrinsic_id);
let (n_tps, inputs, output) = match intrinsic_name {
sym::abort => (0, Vec::new(), tcx.types.never),
sym::unreachable => (0, Vec::new(), tcx.types.never),
diff --git a/compiler/rustc_typeck/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index d8fe63dbf..17c4d0d48 100644
--- a/compiler/rustc_typeck/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -1,104 +1,11 @@
use rustc_ast::InlineAsmTemplatePiece;
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
use rustc_hir as hir;
-use rustc_index::vec::Idx;
-use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy};
use rustc_session::lint;
-use rustc_span::{Span, Symbol, DUMMY_SP};
-use rustc_target::abi::{Pointer, VariantIdx};
+use rustc_span::{Symbol, DUMMY_SP};
use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType};
-use super::FnCtxt;
-
-/// If the type is `Option<T>`, it will return `T`, otherwise
-/// the type itself. Works on most `Option`-like types.
-fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
- let ty::Adt(def, substs) = *ty.kind() else { return ty };
-
- if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() {
- let data_idx;
-
- let one = VariantIdx::new(1);
- let zero = VariantIdx::new(0);
-
- if def.variant(zero).fields.is_empty() {
- data_idx = one;
- } else if def.variant(one).fields.is_empty() {
- data_idx = zero;
- } else {
- return ty;
- }
-
- if def.variant(data_idx).fields.len() == 1 {
- return def.variant(data_idx).fields[0].ty(tcx, substs);
- }
- }
-
- ty
-}
-
-impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
- pub fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) {
- let convert = |ty: Ty<'tcx>| {
- let ty = self.resolve_vars_if_possible(ty);
- let ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
- (SizeSkeleton::compute(ty, self.tcx, self.param_env), ty)
- };
- let (sk_from, from) = convert(from);
- let (sk_to, to) = convert(to);
-
- // Check for same size using the skeletons.
- if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
- if sk_from.same_size(sk_to) {
- return;
- }
-
- // Special-case transmuting from `typeof(function)` and
- // `Option<typeof(function)>` to present a clearer error.
- let from = unpack_option_like(self.tcx, from);
- if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&self.tcx) {
- struct_span_err!(self.tcx.sess, span, E0591, "can't transmute zero-sized type")
- .note(&format!("source type: {from}"))
- .note(&format!("target type: {to}"))
- .help("cast with `as` to a pointer instead")
- .emit();
- return;
- }
- }
-
- // Try to display a sensible error with as much information as possible.
- let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
- Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()),
- Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
- Err(LayoutError::Unknown(bad)) => {
- if bad == ty {
- "this type does not have a fixed size".to_owned()
- } else {
- format!("size can vary because of {bad}")
- }
- }
- Err(err) => err.to_string(),
- };
-
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0512,
- "cannot transmute between types of different sizes, \
- or dependently-sized types"
- );
- if from == to {
- 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.emit();
- }
-}
-
pub struct InlineAsmCtxt<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -126,7 +33,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool {
// Type still may have region variables, but `Sized` does not depend
// on those, so just erase them before querying.
- if ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env) {
+ if ty.is_sized(self.tcx, self.param_env) {
return true;
}
if let ty::Foreign(..) = ty.kind() {
@@ -146,7 +53,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
target_features: &FxHashSet<Symbol>,
) -> Option<InlineAsmType> {
let ty = (self.get_operand_ty)(expr);
- if ty.has_infer_types_or_consts() {
+ if ty.has_non_region_infer() {
bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty);
}
let asm_ty_isize = match self.tcx.sess.target.pointer_width {
@@ -221,7 +128,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
// Check that the type implements Copy. The only case where this can
// possibly fail is for SIMD types which don't #[derive(Copy)].
- if !ty.is_copy_modulo_regions(self.tcx.at(expr.span), self.param_env) {
+ 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"));
@@ -328,17 +235,16 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
lint::builtin::ASM_SUB_REGISTER,
expr.hir_id,
spans,
+ "formatting may not be suitable for sub-register argument",
|lint| {
- let msg = "formatting may not be suitable for sub-register argument";
- let mut err = lint.build(msg);
- err.span_label(expr.span, "for this argument");
- err.help(&format!(
+ lint.span_label(expr.span, "for this argument");
+ lint.help(&format!(
"use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`",
));
- err.help(&format!(
+ lint.help(&format!(
"or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`",
));
- err.emit();
+ lint
},
);
}
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index cfae63e4a..2e7b10257 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -62,195 +62,49 @@ a type parameter).
*/
-pub mod _match;
-mod autoderef;
-mod callee;
-pub mod cast;
mod check;
-mod closure;
-pub mod coercion;
mod compare_method;
-pub mod demand;
-mod diverges;
pub mod dropck;
-mod expectation;
-mod expr;
-mod fallback;
-mod fn_ctxt;
-mod gather_locals;
-mod generator_interior;
-mod inherited;
pub mod intrinsic;
-mod intrinsicck;
-pub mod method;
-mod op;
-mod pat;
-mod place_op;
+pub mod intrinsicck;
mod region;
-pub mod rvalue_scopes;
-mod upvar;
pub mod wfcheck;
-pub mod writeback;
-use check::{check_abi, check_fn, check_mod_item_types};
-pub use diverges::Diverges;
-pub use expectation::Expectation;
-pub use fn_ctxt::*;
-pub use inherited::{Inherited, InheritedBuilder};
+pub use check::check_abi;
-use crate::astconv::AstConv;
-use crate::check::gather_locals::GatherLocalsVisitor;
+use check::check_mod_item_types;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{
- pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan,
-};
+use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder};
use rustc_hir as hir;
-use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
-use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
use rustc_index::bit_set::BitSet;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, Ty, TyCtxt, UserType};
-use rustc_session::config;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_session::parse::feature_err;
-use rustc_session::Session;
use rustc_span::source_map::DUMMY_SP;
use rustc_span::symbol::{kw, Ident};
use rustc_span::{self, BytePos, Span, Symbol};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits;
-use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
-use std::cell::RefCell;
use std::num::NonZeroU32;
use crate::require_c_abi_if_c_variadic;
use crate::util::common::indenter;
-use self::coercion::DynamicCoerceMany;
use self::compare_method::collect_trait_impl_trait_tys;
use self::region::region_scope_tree;
-pub use self::Expectation::*;
-
-#[macro_export]
-macro_rules! type_error_struct {
- ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
- let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
-
- if $typ.references_error() {
- err.downgrade_to_delayed_bug();
- }
-
- err
- })
-}
-
-/// The type of a local binding, including the revealed type for anon types.
-#[derive(Copy, Clone, Debug)]
-pub struct LocalTy<'tcx> {
- decl_ty: Ty<'tcx>,
- revealed_ty: Ty<'tcx>,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum Needs {
- MutPlace,
- None,
-}
-
-impl Needs {
- fn maybe_mut_place(m: hir::Mutability) -> Self {
- match m {
- hir::Mutability::Mut => Needs::MutPlace,
- hir::Mutability::Not => Needs::None,
- }
- }
-}
-
-#[derive(Copy, Clone)]
-pub struct UnsafetyState {
- pub def: hir::HirId,
- pub unsafety: hir::Unsafety,
- from_fn: bool,
-}
-
-impl UnsafetyState {
- pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
- UnsafetyState { def, unsafety, from_fn: true }
- }
-
- pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
- use hir::BlockCheckMode;
- match self.unsafety {
- // If this unsafe, then if the outer function was already marked as
- // unsafe we shouldn't attribute the unsafe'ness to the block. This
- // way the block can be warned about instead of ignoring this
- // extraneous block (functions are never warned about).
- hir::Unsafety::Unsafe if self.from_fn => self,
-
- unsafety => {
- let (unsafety, def) = match blk.rules {
- BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
- BlockCheckMode::DefaultBlock => (unsafety, self.def),
- };
- UnsafetyState { def, unsafety, from_fn: false }
- }
- }
- }
-}
-
-#[derive(Debug, Copy, Clone)]
-pub enum PlaceOp {
- Deref,
- Index,
-}
-
-pub struct BreakableCtxt<'tcx> {
- may_break: bool,
-
- // this is `null` for loops where break with a value is illegal,
- // such as `while`, `for`, and `while let`
- coerce: Option<DynamicCoerceMany<'tcx>>,
-}
-
-pub struct EnclosingBreakables<'tcx> {
- stack: Vec<BreakableCtxt<'tcx>>,
- by_id: HirIdMap<usize>,
-}
-
-impl<'tcx> EnclosingBreakables<'tcx> {
- fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
- self.opt_find_breakable(target_id).unwrap_or_else(|| {
- bug!("could not find enclosing breakable with id {}", target_id);
- })
- }
-
- fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
- match self.by_id.get(&target_id) {
- Some(ix) => Some(&mut self.stack[*ix]),
- None => None,
- }
- }
-}
pub fn provide(providers: &mut Providers) {
- method::provide(providers);
wfcheck::provide(providers);
*providers = Providers {
- typeck_item_bodies,
- typeck_const_arg,
- typeck,
- diagnostic_only_typeck,
- has_typeck_results,
adt_destructor,
- used_trait_imports,
check_mod_item_types,
region_scope_tree,
collect_trait_impl_trait_tys,
+ compare_assoc_const_impl_item_with_trait_item: compare_method::raw_compare_const_impl,
..*providers
};
}
@@ -259,255 +113,6 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
tcx.calculate_dtor(def_id, dropck::check_drop_impl)
}
-/// If this `DefId` is a "primary tables entry", returns
-/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
-///
-/// If this function returns `Some`, then `typeck_results(def_id)` will
-/// succeed; if it returns `None`, then `typeck_results(def_id)` may or
-/// may not succeed. In some cases where this function returns `None`
-/// (notably closures), `typeck_results(def_id)` would wind up
-/// redirecting to the owning function.
-fn primary_body_of(
- tcx: TyCtxt<'_>,
- id: hir::HirId,
-) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
- match tcx.hir().get(id) {
- Node::Item(item) => match item.kind {
- hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
- Some((body, Some(ty), None))
- }
- hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
- _ => None,
- },
- Node::TraitItem(item) => match item.kind {
- hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
- hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
- Some((body, None, Some(sig)))
- }
- _ => None,
- },
- Node::ImplItem(item) => match item.kind {
- hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
- hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
- _ => None,
- },
- Node::AnonConst(constant) => Some((constant.body, None, None)),
- _ => None,
- }
-}
-
-fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
- // Closures' typeck results come from their outermost function,
- // as they are part of the same "inference environment".
- let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
- if typeck_root_def_id != def_id {
- return tcx.has_typeck_results(typeck_root_def_id);
- }
-
- if let Some(def_id) = def_id.as_local() {
- let id = tcx.hir().local_def_id_to_hir_id(def_id);
- primary_body_of(tcx, id).is_some()
- } else {
- false
- }
-}
-
-fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
- &*tcx.typeck(def_id).used_trait_imports
-}
-
-fn typeck_const_arg<'tcx>(
- tcx: TyCtxt<'tcx>,
- (did, param_did): (LocalDefId, DefId),
-) -> &ty::TypeckResults<'tcx> {
- let fallback = move || tcx.type_of(param_did);
- 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());
- typeck_with_fallback(tcx, def_id, fallback)
- }
-}
-
-/// Used only to get `TypeckResults` for type inference during error recovery.
-/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
-fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
- let fallback = move || {
- let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
- tcx.ty_error_with_message(span, "diagnostic only typeck table used")
- };
- typeck_with_fallback(tcx, def_id, fallback)
-}
-
-fn typeck_with_fallback<'tcx>(
- tcx: TyCtxt<'tcx>,
- def_id: LocalDefId,
- fallback: impl Fn() -> Ty<'tcx> + 'tcx,
-) -> &'tcx ty::TypeckResults<'tcx> {
- // Closures' typeck results come from their outermost function,
- // as they are part of the same "inference environment".
- let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
- if typeck_root_def_id != def_id {
- return tcx.typeck(typeck_root_def_id);
- }
-
- let id = tcx.hir().local_def_id_to_hir_id(def_id);
- let span = tcx.hir().span(id);
-
- // Figure out what primary body this item has.
- let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
- span_bug!(span, "can't type-check body of {:?}", def_id);
- });
- let body = tcx.hir().body(body_id);
-
- let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
- let param_env = tcx.param_env(def_id);
- let fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
- let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
- let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
- <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
- } else {
- tcx.fn_sig(def_id)
- };
-
- check_abi(tcx, id, span, fn_sig.abi());
-
- // Compute the function signature from point of view of inside the fn.
- let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
- let fn_sig = inh.normalize_associated_types_in(
- body.value.span,
- body_id.hir_id,
- param_env,
- fn_sig,
- );
- check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
- } else {
- let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
- let expected_type = body_ty
- .and_then(|ty| match ty.kind {
- hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
- _ => None,
- })
- .unwrap_or_else(|| match tcx.hir().get(id) {
- Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
- Node::Expr(&hir::Expr {
- kind: hir::ExprKind::ConstBlock(ref anon_const),
- ..
- }) if anon_const.hir_id == id => 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 => fcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::TypeInference,
- span,
- }),
- Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
- | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
- let operand_ty = asm
- .operands
- .iter()
- .filter_map(|(op, _op_sp)| match op {
- hir::InlineAsmOperand::Const { anon_const }
- if anon_const.hir_id == id =>
- {
- // Inline assembly constants must be integers.
- Some(fcx.next_int_var())
- }
- hir::InlineAsmOperand::SymFn { anon_const }
- if anon_const.hir_id == id =>
- {
- Some(fcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
- span,
- }))
- }
- _ => None,
- })
- .next();
- operand_ty.unwrap_or_else(fallback)
- }
- _ => fallback(),
- },
- _ => fallback(),
- });
-
- let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
- fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
-
- // Gather locals in statics (because of block expressions).
- GatherLocalsVisitor::new(&fcx).visit_body(body);
-
- fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
-
- fcx.write_ty(id, expected_type);
-
- fcx
- };
-
- let fallback_has_occurred = fcx.type_inference_fallback();
-
- // Even though coercion casts provide type hints, we check casts after fallback for
- // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
- fcx.check_casts();
- fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
-
- // Closure and generator analysis may run after fallback
- // because they don't constrain other type variables.
- fcx.closure_analyze(body);
- assert!(fcx.deferred_call_resolutions.borrow().is_empty());
- // Before the generator analysis, temporary scopes shall be marked to provide more
- // precise information on types to be captured.
- fcx.resolve_rvalue_scopes(def_id.to_def_id());
- fcx.resolve_generator_interiors(def_id.to_def_id());
-
- for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
- let ty = fcx.normalize_ty(span, ty);
- fcx.require_type_is_sized(ty, span, code);
- }
-
- fcx.select_all_obligations_or_error();
-
- if !fcx.infcx.is_tainted_by_errors() {
- fcx.check_transmutes();
- }
-
- fcx.check_asms();
-
- fcx.infcx.skip_region_resolution();
-
- fcx.resolve_type_vars_in_body(body)
- });
-
- // Consistency check our TypeckResults instance can hold all ItemLocalIds
- // it will need to hold.
- assert_eq!(typeck_results.hir_owner, id.owner);
-
- typeck_results
-}
-
-/// When `check_fn` is invoked on a generator (i.e., a body that
-/// includes yield), it returns back some information about the yield
-/// points.
-struct GeneratorTypes<'tcx> {
- /// Type of generator argument / values returned by `yield`.
- resume_ty: Ty<'tcx>,
-
- /// Type of value that is yielded.
- yield_ty: Ty<'tcx>,
-
- /// Types that are captured (see `GeneratorInterior` for more).
- interior: Ty<'tcx>,
-
- /// Indicates if the generator is movable or static (immovable).
- movability: hir::Movability,
-}
-
/// Given a `DefId` for an opaque type in return position, find its parent item's return
/// expressions.
fn get_owner_return_paths<'tcx>(
@@ -515,7 +120,7 @@ fn get_owner_return_paths<'tcx>(
def_id: LocalDefId,
) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let parent_id = tcx.hir().get_parent_item(hir_id);
+ let parent_id = tcx.hir().get_parent_item(hir_id).def_id;
tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
let body = tcx.hir().body(body_id);
let mut visitor = ReturnsVisitor::default();
@@ -524,9 +129,10 @@ fn get_owner_return_paths<'tcx>(
})
}
-// Forbid defining intrinsics in Rust code,
-// as they must always be defined by the compiler.
-fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
+/// Forbid defining intrinsics in Rust code,
+/// as they must always be defined by the compiler.
+// FIXME: Move this to a more appropriate place.
+pub fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
}
@@ -820,6 +426,17 @@ fn fn_sig_suggestion<'tcx>(
format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
}
+pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
+ Some(match ty.kind() {
+ ty::Bool => "true",
+ ty::Char => "'a'",
+ ty::Int(_) | ty::Uint(_) => "42",
+ ty::Float(_) => "3.14159",
+ ty::Error(_) | ty::Never => return None,
+ _ => "value",
+ })
+}
+
/// 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.
@@ -841,7 +458,7 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
ty::AssocKind::Const => {
let ty = tcx.type_of(assoc.def_id);
- let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
+ let val = ty_kind_suggestion(ty).unwrap_or("value");
format!("const {}: {} = {};", assoc.name, ty, val)
}
}
@@ -892,76 +509,7 @@ fn bad_non_zero_sized_fields<'tcx>(
err.emit();
}
-fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
- struct_span_err!(
- tcx.sess,
- span,
- E0533,
- "expected unit struct, unit variant or constant, found {} `{}`",
- res.descr(),
- rustc_hir_pretty::qpath_to_string(qpath),
- )
- .emit();
-}
-
-/// Controls whether the arguments are tupled. This is used for the call
-/// operator.
-///
-/// Tupling means that all call-side arguments are packed into a tuple and
-/// passed as a single parameter. For example, if tupling is enabled, this
-/// function:
-/// ```
-/// fn f(x: (isize, isize)) {}
-/// ```
-/// Can be called as:
-/// ```ignore UNSOLVED (can this be done in user code?)
-/// # fn f(x: (isize, isize)) {}
-/// f(1, 2);
-/// ```
-/// Instead of:
-/// ```
-/// # fn f(x: (isize, isize)) {}
-/// f((1, 2));
-/// ```
-#[derive(Clone, Eq, PartialEq)]
-enum TupleArgumentsFlag {
- DontTupleArguments,
- TupleArguments,
-}
-
-fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
- tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
-}
-
-fn fatally_break_rust(sess: &Session) {
- let handler = sess.diagnostic();
- handler.span_bug_no_panic(
- MultiSpan::new(),
- "It looks like you're trying to break rust; would you like some ICE?",
- );
- handler.note_without_error("the compiler expectedly panicked. this is a feature.");
- handler.note_without_error(
- "we would appreciate a joke overview: \
- https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
- );
- handler.note_without_error(&format!(
- "rustc {} running on {}",
- option_env!("CFG_VERSION").unwrap_or("unknown_version"),
- config::host_triple(),
- ));
-}
-
-fn potentially_plural_count(count: usize, word: &str) -> String {
+// FIXME: Consider moving this method to a more fitting place.
+pub fn potentially_plural_count(count: usize, word: &str) -> String {
format!("{} {}{}", count, word, pluralize!(count))
}
-
-fn has_expected_num_generic_args<'tcx>(
- tcx: TyCtxt<'tcx>,
- 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 }
- })
-}
diff --git a/compiler/rustc_typeck/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index b89db79be..ff32329e4 100644
--- a/compiler/rustc_typeck/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -252,9 +252,13 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
) => {
// For shortcircuiting operators, mark the RHS as a terminating
// scope since it only executes conditionally.
- terminating(r.hir_id.local_id);
- }
+ // `Let` expressions (in a let-chain) shouldn't be terminating, as their temporaries
+ // should live beyond the immediate expression
+ if !matches!(r.kind, hir::ExprKind::Let(_)) {
+ terminating(r.hir_id.local_id);
+ }
+ }
hir::ExprKind::If(_, ref then, Some(ref otherwise)) => {
terminating(then.hir_id.local_id);
terminating(otherwise.hir_id.local_id);
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 27b3da8ab..a23575004 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -12,17 +12,17 @@ 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::ty::subst::{GenericArgKind, InternalSubsts, Subst};
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{
self, AdtKind, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable,
TypeSuperVisitable, TypeVisitable, TypeVisitor,
};
+use rustc_middle::ty::{GenericArgKind, InternalSubsts};
use rustc_session::parse::feature_err;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::autoderef::Autoderef;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{
@@ -91,32 +91,31 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
{
let param_env = tcx.param_env(body_def_id);
let body_id = tcx.hir().local_def_id_to_hir_id(body_def_id);
- tcx.infer_ctxt().enter(|ref infcx| {
- let ocx = ObligationCtxt::new(infcx);
+ let infcx = &tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(infcx);
- let assumed_wf_types = ocx.assumed_wf_types(param_env, span, body_def_id);
+ let assumed_wf_types = ocx.assumed_wf_types(param_env, span, body_def_id);
- let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env };
+ let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env };
- if !tcx.features().trivial_bounds {
- wfcx.check_false_global_bounds()
- }
- f(&mut wfcx);
- let errors = wfcx.select_all_or_error();
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- return;
- }
+ if !tcx.features().trivial_bounds {
+ wfcx.check_false_global_bounds()
+ }
+ f(&mut wfcx);
+ let errors = wfcx.select_all_or_error();
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ return;
+ }
- let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types);
- let outlives_environment =
- OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
+ let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types);
+ let outlives_environment =
+ OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
- infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
- })
+ infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
}
-fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
let node = tcx.hir().expect_owner(def_id);
match node {
hir::OwnerNode::Crate(_) => {}
@@ -148,10 +147,10 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
/// the types first.
#[instrument(skip(tcx), level = "debug")]
fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
- let def_id = item.def_id;
+ let def_id = item.owner_id.def_id;
debug!(
- ?item.def_id,
+ ?item.owner_id,
item.name = ? tcx.def_path_str(def_id.to_def_id())
);
@@ -175,7 +174,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
// for `T`
hir::ItemKind::Impl(ref impl_) => {
let is_auto = tcx
- .impl_trait_ref(item.def_id)
+ .impl_trait_ref(def_id)
.map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.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);
@@ -211,13 +210,13 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
}
}
hir::ItemKind::Fn(ref sig, ..) => {
- check_item_fn(tcx, item.def_id, item.ident, item.span, sig.decl);
+ check_item_fn(tcx, def_id, item.ident, item.span, sig.decl);
}
hir::ItemKind::Static(ty, ..) => {
- check_item_type(tcx, item.def_id, ty.span, false);
+ check_item_type(tcx, def_id, ty.span, false);
}
hir::ItemKind::Const(ty, ..) => {
- check_item_type(tcx, item.def_id, ty.span, false);
+ check_item_type(tcx, def_id, ty.span, false);
}
hir::ItemKind::Struct(ref struct_def, ref ast_generics) => {
check_type_defn(tcx, item, false, |wfcx| vec![wfcx.non_enum_variant(struct_def)]);
@@ -247,24 +246,24 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
}
fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) {
- let def_id = item.def_id;
+ let def_id = item.owner_id.def_id;
debug!(
- ?item.def_id,
+ ?item.owner_id,
item.name = ? tcx.def_path_str(def_id.to_def_id())
);
match item.kind {
hir::ForeignItemKind::Fn(decl, ..) => {
- check_item_fn(tcx, item.def_id, item.ident, item.span, decl)
+ check_item_fn(tcx, def_id, item.ident, item.span, decl)
}
- hir::ForeignItemKind::Static(ty, ..) => check_item_type(tcx, item.def_id, ty.span, true),
+ hir::ForeignItemKind::Static(ty, ..) => check_item_type(tcx, def_id, ty.span, true),
hir::ForeignItemKind::Type => (),
}
}
fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
- let def_id = trait_item.def_id;
+ let def_id = trait_item.owner_id.def_id;
let (method_sig, span) = match trait_item.kind {
hir::TraitItemKind::Fn(ref sig, _) => (Some(sig), trait_item.span),
@@ -272,11 +271,11 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
_ => (None, trait_item.span),
};
check_object_unsafe_self_trait_by_name(tcx, trait_item);
- check_associated_item(tcx, trait_item.def_id, span, method_sig);
+ check_associated_item(tcx, def_id, span, method_sig);
let encl_trait_def_id = tcx.local_parent(def_id);
let encl_trait = tcx.hir().expect_item(encl_trait_def_id);
- let encl_trait_def_id = encl_trait.def_id.to_def_id();
+ let encl_trait_def_id = encl_trait.owner_id.to_def_id();
let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() {
Some("fn")
} else if Some(encl_trait_def_id) == tcx.lang_items().fn_mut_trait() {
@@ -349,7 +348,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
loop {
let mut should_continue = false;
for gat_item in associated_items {
- let gat_def_id = gat_item.id.def_id;
+ let gat_def_id = gat_item.id.owner_id;
let gat_item = tcx.associated_item(gat_def_id);
// If this item is not an assoc ty, or has no substs, then it's not a GAT
if gat_item.kind != ty::AssocKind::Type {
@@ -366,7 +365,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
// constrains the GAT with individually.
let mut new_required_bounds: Option<FxHashSet<ty::Predicate<'_>>> = None;
for item in associated_items {
- let item_def_id = item.id.def_id;
+ let item_def_id = item.id.owner_id;
// Skip our own GAT, since it does not constrain itself at all.
if item_def_id == gat_def_id {
continue;
@@ -393,7 +392,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
// We also assume that all of the function signature's parameter types
// are well formed.
&sig.inputs().iter().copied().collect(),
- gat_def_id,
+ gat_def_id.def_id,
gat_generics,
)
}
@@ -416,7 +415,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
.copied()
.collect::<Vec<_>>(),
&FxHashSet::default(),
- gat_def_id,
+ gat_def_id.def_id,
gat_generics,
)
}
@@ -456,7 +455,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
}
for (gat_def_id, required_bounds) in required_bounds_by_item {
- let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id);
+ let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id.def_id);
debug!(?required_bounds);
let param_env = tcx.param_env(gat_def_id);
let gat_hir = gat_item_hir.hir_id();
@@ -699,29 +698,32 @@ fn resolve_regions_with_wf_tys<'tcx>(
id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
wf_tys: &FxHashSet<Ty<'tcx>>,
- add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'a, 'tcx>, &'a RegionBoundPairs<'tcx>),
+ add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'tcx>, &'a RegionBoundPairs<'tcx>),
) -> bool {
// Unfortunately, we have to use a new `InferCtxt` each call, because
// region constraints get added and solved there and we need to test each
// call individually.
- tcx.infer_ctxt().enter(|infcx| {
- let outlives_environment = OutlivesEnvironment::with_bounds(
- param_env,
- Some(&infcx),
- infcx.implied_bounds_tys(param_env, id, wf_tys.clone()),
- );
- let region_bound_pairs = outlives_environment.region_bound_pairs();
+ let infcx = tcx.infer_ctxt().build();
+ let outlives_environment = OutlivesEnvironment::with_bounds(
+ param_env,
+ Some(&infcx),
+ infcx.implied_bounds_tys(param_env, id, wf_tys.clone()),
+ );
+ let region_bound_pairs = outlives_environment.region_bound_pairs();
- add_constraints(&infcx, region_bound_pairs);
+ add_constraints(&infcx, region_bound_pairs);
- let errors = infcx.resolve_regions(&outlives_environment);
+ infcx.process_registered_region_obligations(
+ outlives_environment.region_bound_pairs(),
+ param_env,
+ );
+ let errors = infcx.resolve_regions(&outlives_environment);
- debug!(?errors, "errors");
+ debug!(?errors, "errors");
- // If we were able to prove that the type outlives the region without
- // an error, it must be because of the implied or explicit bounds...
- errors.is_empty()
- })
+ // If we were able to prove that the type outlives the region without
+ // an error, it must be because of the implied or explicit bounds...
+ errors.is_empty()
}
/// TypeVisitor that looks for uses of GATs like
@@ -786,9 +788,9 @@ fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
/// When this is done, suggest using `Self` instead.
fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) {
let (trait_name, trait_def_id) =
- match tcx.hir().get_by_def_id(tcx.hir().get_parent_item(item.hir_id())) {
+ match tcx.hir().get_by_def_id(tcx.hir().get_parent_item(item.hir_id()).def_id) {
hir::Node::Item(item) => match item.kind {
- hir::ItemKind::Trait(..) => (item.ident, item.def_id),
+ hir::ItemKind::Trait(..) => (item.ident, item.owner_id),
_ => return,
},
_ => return,
@@ -796,18 +798,18 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
let mut trait_should_be_self = vec![];
match &item.kind {
hir::TraitItemKind::Const(ty, _) | hir::TraitItemKind::Type(_, Some(ty))
- if could_be_self(trait_def_id, ty) =>
+ if could_be_self(trait_def_id.def_id, ty) =>
{
trait_should_be_self.push(ty.span)
}
hir::TraitItemKind::Fn(sig, _) => {
for ty in sig.decl.inputs {
- if could_be_self(trait_def_id, ty) {
+ if could_be_self(trait_def_id.def_id, ty) {
trait_should_be_self.push(ty.span);
}
}
match sig.decl.output {
- hir::FnRetTy::Return(ty) if could_be_self(trait_def_id, ty) => {
+ hir::FnRetTy::Return(ty) if could_be_self(trait_def_id.def_id, ty) => {
trait_should_be_self.push(ty.span);
}
_ => {}
@@ -836,16 +838,14 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
}
fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) {
- let def_id = impl_item.def_id;
-
let (method_sig, span) = match impl_item.kind {
hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span),
// Constrain binding and overflow error spans to `<Ty>` in `type foo = <Ty>`.
- hir::ImplItemKind::TyAlias(ty) if ty.span != DUMMY_SP => (None, ty.span),
+ hir::ImplItemKind::Type(ty) if ty.span != DUMMY_SP => (None, ty.span),
_ => (None, impl_item.span),
};
- check_associated_item(tcx, def_id, span, method_sig);
+ check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig);
}
fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
@@ -1045,9 +1045,11 @@ fn check_type_defn<'tcx, F>(
) where
F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec<AdtVariant<'tcx>>,
{
- enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| {
+ let _ = tcx.representability(item.owner_id.def_id);
+
+ enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
let variants = lookup_fields(wfcx);
- let packed = tcx.adt_def(item.def_id).repr().packed();
+ let packed = tcx.adt_def(item.owner_id).repr().packed();
for variant in &variants {
// All field types must be well-formed.
@@ -1071,7 +1073,7 @@ fn check_type_defn<'tcx, F>(
// Just treat unresolved type expression as if it needs drop.
true
} else {
- ty.needs_drop(tcx, tcx.param_env(item.def_id))
+ ty.needs_drop(tcx, tcx.param_env(item.owner_id))
}
}
};
@@ -1103,8 +1105,6 @@ fn check_type_defn<'tcx, F>(
// Explicit `enum` discriminant values must const-evaluate successfully.
if let Some(discr_def_id) = variant.explicit_discr {
- let discr_substs = InternalSubsts::identity_for_item(tcx, discr_def_id.to_def_id());
-
let cause = traits::ObligationCause::new(
tcx.def_span(discr_def_id),
wfcx.body_id,
@@ -1113,28 +1113,28 @@ fn check_type_defn<'tcx, F>(
wfcx.register_obligation(traits::Obligation::new(
cause,
wfcx.param_env,
- ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new(
- ty::WithOptConstParam::unknown(discr_def_id.to_def_id()),
- discr_substs,
- )))
+ ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
+ ty::Const::from_anon_const(tcx, discr_def_id),
+ ))
.to_predicate(tcx),
));
}
}
- check_where_clauses(wfcx, item.span, item.def_id);
+ check_where_clauses(wfcx, item.span, item.owner_id.def_id);
});
}
#[instrument(skip(tcx, item))]
fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
- debug!(?item.def_id);
+ debug!(?item.owner_id);
- let trait_def = tcx.trait_def(item.def_id);
+ let def_id = item.owner_id.def_id;
+ let trait_def = tcx.trait_def(def_id);
if trait_def.is_marker
|| matches!(trait_def.specialization_kind, TraitSpecializationKind::Marker)
{
- for associated_def_id in &*tcx.associated_item_def_ids(item.def_id) {
+ for associated_def_id in &*tcx.associated_item_def_ids(def_id) {
struct_span_err!(
tcx.sess,
tcx.def_span(*associated_def_id),
@@ -1145,8 +1145,8 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
}
}
- enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| {
- check_where_clauses(wfcx, item.span, item.def_id)
+ enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| {
+ check_where_clauses(wfcx, item.span, def_id)
});
// Only check traits, don't check trait aliases
@@ -1240,13 +1240,13 @@ fn check_impl<'tcx>(
ast_trait_ref: &Option<hir::TraitRef<'_>>,
constness: hir::Constness,
) {
- enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| {
+ enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
match *ast_trait_ref {
Some(ref ast_trait_ref) => {
// `#[rustc_reservation_impl]` impls are not real impls and
// therefore don't need to be WF (the trait's `Self: Trait` predicate
// won't hold).
- let trait_ref = tcx.impl_trait_ref(item.def_id).unwrap();
+ let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap();
let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref);
let trait_pred = ty::TraitPredicate {
trait_ref,
@@ -1268,21 +1268,21 @@ fn check_impl<'tcx>(
wfcx.register_obligations(obligations);
}
None => {
- let self_ty = tcx.type_of(item.def_id);
+ let self_ty = tcx.type_of(item.owner_id);
let self_ty = wfcx.normalize(
item.span,
- Some(WellFormedLoc::Ty(item.hir_id().expect_owner())),
+ Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
self_ty,
);
wfcx.register_wf_obligation(
ast_self_ty.span,
- Some(WellFormedLoc::Ty(item.hir_id().expect_owner())),
+ Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
self_ty.into(),
);
}
}
- check_where_clauses(wfcx, item.span, item.def_id);
+ check_where_clauses(wfcx, item.span, item.owner_id.def_id);
});
}
@@ -1427,9 +1427,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
let substituted_pred = predicates.rebind(pred).subst(tcx, substs);
// Don't check non-defaulted params, dependent defaults (including lifetimes)
// or preds with multiple params.
- if substituted_pred.has_param_types_or_consts()
- || param_count.params.len() > 1
- || has_region
+ if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region
{
None
} else if predicates.0.predicates.iter().any(|&(p, _)| p == substituted_pred) {
@@ -1678,7 +1676,7 @@ fn receiver_is_valid<'tcx>(
// `self: Self` is always valid.
if can_eq_self(receiver_ty) {
if let Err(err) = wfcx.equate_types(&cause, wfcx.param_env, self_ty, receiver_ty) {
- infcx.report_mismatched_types(&cause, self_ty, receiver_ty, err).emit();
+ infcx.err_ctxt().report_mismatched_types(&cause, self_ty, receiver_ty, err).emit();
}
return true;
}
@@ -1710,7 +1708,10 @@ fn receiver_is_valid<'tcx>(
if let Err(err) =
wfcx.equate_types(&cause, wfcx.param_env, self_ty, potential_self_ty)
{
- infcx.report_mismatched_types(&cause, self_ty, potential_self_ty, err).emit();
+ infcx
+ .err_ctxt()
+ .report_mismatched_types(&cause, self_ty, potential_self_ty, err)
+ .emit();
}
break;
@@ -1777,14 +1778,14 @@ fn check_variances_for_type_defn<'tcx>(
item: &hir::Item<'tcx>,
hir_generics: &hir::Generics<'_>,
) {
- let ty = tcx.type_of(item.def_id);
+ let ty = tcx.type_of(item.owner_id);
if tcx.has_error_field(ty) {
return;
}
- let ty_predicates = tcx.predicates_of(item.def_id);
+ let ty_predicates = tcx.predicates_of(item.owner_id);
assert_eq!(ty_predicates.parent, None);
- let variances = tcx.variances_of(item.def_id);
+ let variances = tcx.variances_of(item.owner_id);
let mut constrained_parameters: FxHashSet<_> = variances
.iter()
@@ -1797,7 +1798,7 @@ fn check_variances_for_type_defn<'tcx>(
// Lazily calculated because it is only needed in case of an error.
let explicitly_bounded_params = LazyCell::new(|| {
- let icx = crate::collect::ItemCtxt::new(tcx, item.def_id.to_def_id());
+ let icx = crate::collect::ItemCtxt::new(tcx, item.owner_id.to_def_id());
hir_generics
.predicates
.iter()
@@ -1918,10 +1919,10 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalDefId) {
let items = tcx.hir_module_items(module);
- items.par_items(|item| tcx.ensure().check_well_formed(item.def_id));
- items.par_impl_items(|item| tcx.ensure().check_well_formed(item.def_id));
- items.par_trait_items(|item| tcx.ensure().check_well_formed(item.def_id));
- items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.def_id));
+ items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id));
+ items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id));
+ items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id));
+ items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id));
}
///////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_typeck/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs
index 1d23ed929..d0c317334 100644
--- a/compiler/rustc_typeck/src/check_unused.rs
+++ b/compiler/rustc_hir_analysis/src/check_unused.rs
@@ -1,5 +1,6 @@
use crate::errors::{ExternCrateNotIdiomatic, UnusedExternCrate};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::unord::UnordSet;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -8,12 +9,12 @@ use rustc_session::lint;
use rustc_span::{Span, Symbol};
pub fn check_crate(tcx: TyCtxt<'_>) {
- let mut used_trait_imports: FxHashSet<LocalDefId> = FxHashSet::default();
+ let mut used_trait_imports: UnordSet<LocalDefId> = Default::default();
for item_def_id in tcx.hir().body_owners() {
let imports = tcx.used_trait_imports(item_def_id);
debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
- used_trait_imports.extend(imports.iter());
+ used_trait_imports.extend(imports.items().copied());
}
for &id in tcx.maybe_unused_trait_imports(()) {
@@ -29,14 +30,18 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
continue;
}
let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() };
- tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| {
- let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
- format!("unused import: `{}`", snippet)
- } else {
- "unused import".to_owned()
- };
- lint.build(&msg).emit();
- });
+ let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
+ format!("unused import: `{}`", snippet)
+ } else {
+ "unused import".to_owned()
+ };
+ tcx.struct_span_lint_hir(
+ lint::builtin::UNUSED_IMPORTS,
+ item.hir_id(),
+ path.span,
+ msg,
+ |lint| lint,
+ );
}
unused_crates_lint(tcx);
@@ -85,11 +90,11 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
let mut crates_to_lint = vec![];
for id in tcx.hir().items() {
- if matches!(tcx.def_kind(id.def_id), DefKind::ExternCrate) {
+ if matches!(tcx.def_kind(id.owner_id), DefKind::ExternCrate) {
let item = tcx.hir().item(id);
if let hir::ItemKind::ExternCrate(orig_name) = item.kind {
crates_to_lint.push(ExternCrateToLint {
- def_id: item.def_id.to_def_id(),
+ def_id: item.owner_id.to_def_id(),
span: item.span,
orig_name,
warn_if_unused: !item.ident.as_str().starts_with('_'),
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
new file mode 100644
index 000000000..b6c91d425
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -0,0 +1,572 @@
+//! 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 rustc_errors::{struct_span_err, MultiSpan};
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::ItemKind;
+use rustc_infer::infer;
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
+use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitable};
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
+use rustc_trait_selection::traits::predicate_for_trait_def;
+use rustc_trait_selection::traits::{self, ObligationCause};
+use std::collections::BTreeMap;
+
+pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
+ let lang_items = tcx.lang_items();
+ 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.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)
+ .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn);
+}
+
+struct Checker<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ trait_def_id: DefId,
+}
+
+impl<'tcx> Checker<'tcx> {
+ fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self
+ where
+ F: FnMut(TyCtxt<'tcx>, LocalDefId),
+ {
+ if Some(self.trait_def_id) == trait_def_id {
+ for &impl_def_id in self.tcx.hir().trait_impls(self.trait_def_id) {
+ f(self.tcx, impl_def_id);
+ }
+ }
+ self
+ }
+}
+
+fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
+ // Destructors only work on local ADT types.
+ match tcx.type_of(impl_did).kind() {
+ ty::Adt(def, _) if def.did().is_local() => return,
+ ty::Error(_) => return,
+ _ => {}
+ }
+
+ let sp = match tcx.hir().expect_item(impl_did).kind {
+ ItemKind::Impl(ref impl_) => impl_.self_ty.span,
+ _ => bug!("expected Drop impl item"),
+ };
+
+ tcx.sess.emit_err(DropImplOnWrongItem { span: sp });
+}
+
+fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
+ debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
+
+ let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
+
+ let self_type = tcx.type_of(impl_did);
+ debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);
+
+ let param_env = tcx.param_env(impl_did);
+ assert!(!self_type.has_escaping_bound_vars());
+
+ 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 cause = traits::ObligationCause::misc(span, impl_hir_id);
+ match can_type_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` may not 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![];
+
+ for (field, ty) in fields {
+ let field_span = tcx.def_span(field.did);
+ let field_ty_span = match tcx.hir().get_if_local(field.did) {
+ Some(hir::Node::Field(field_def)) => field_def.ty.span,
+ _ => field_span,
+ };
+ err.span_label(field_span, "this field does not implement `Copy`");
+ // Spin up a new FulfillmentContext, so we can get the _precise_ reason
+ // why this field does not implement Copy. This is useful because sometimes
+ // it is not immediately clear why Copy is not implemented for a field, since
+ // all we point at is the field itself.
+ let infcx = tcx.infer_ctxt().ignoring_regions().build();
+ for error in traits::fully_solve_bound(
+ &infcx,
+ traits::ObligationCause::dummy_with_span(field_ty_span),
+ param_env,
+ ty,
+ tcx.lang_items().copy_trait().unwrap(),
+ ) {
+ 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::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),
+ ));
+ }
+ }
+ }
+ }
+ 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)
+ }),
+ );
+ err.emit();
+ }
+ Err(CopyImplementationError::NotAnAdt) => {
+ tcx.sess.emit_err(CopyImplOnNonAdt { span });
+ }
+ Err(CopyImplementationError::HasDestructor) => {
+ tcx.sess.emit_err(CopyImplOnTypeWithDtor { span });
+ }
+ }
+}
+
+fn visit_implementation_of_coerce_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) {
+ debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
+
+ // Just compute this for the side-effects, in particular reporting
+ // errors; other parts of the code may demand it for the info of
+ // course.
+ let span = tcx.def_span(impl_did);
+ tcx.at(span).coerce_unsized_info(impl_did);
+}
+
+fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) {
+ debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
+
+ let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
+ let span = tcx.hir().span(impl_hir_id);
+
+ let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span));
+
+ let source = tcx.type_of(impl_did);
+ assert!(!source.has_escaping_bound_vars());
+ let target = {
+ let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+ assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
+
+ trait_ref.substs.type_at(1)
+ };
+
+ debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target);
+
+ let param_env = tcx.param_env(impl_did);
+
+ let create_err = |msg: &str| struct_span_err!(tcx.sess, span, E0378, "{}", msg);
+
+ let infcx = tcx.infer_ctxt().build();
+ let cause = ObligationCause::misc(span, impl_hir_id);
+
+ use rustc_type_ir::sty::TyKind::*;
+ match (source.kind(), target.kind()) {
+ (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
+ if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {}
+ (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (),
+ (&Adt(def_a, substs_a), &Adt(def_b, substs_b))
+ if def_a.is_struct() && def_b.is_struct() =>
+ {
+ if def_a != def_b {
+ let source_path = tcx.def_path_str(def_a.did());
+ let target_path = tcx.def_path_str(def_b.did());
+
+ create_err(&format!(
+ "the trait `DispatchFromDyn` may only be implemented \
+ for a coercion between structures with the same \
+ definition; expected `{}`, found `{}`",
+ source_path, target_path,
+ ))
+ .emit();
+
+ return;
+ }
+
+ if def_a.repr().c() || def_a.repr().packed() {
+ create_err(
+ "structs implementing `DispatchFromDyn` may not have \
+ `#[repr(packed)]` or `#[repr(C)]`",
+ )
+ .emit();
+ }
+
+ let fields = &def_a.non_enum_variant().fields;
+
+ let coerced_fields = fields
+ .iter()
+ .filter(|field| {
+ let ty_a = field.ty(tcx, substs_a);
+ let ty_b = field.ty(tcx, substs_b);
+
+ if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
+ if layout.is_zst() && layout.align.abi.bytes() == 1 {
+ // ignore ZST fields with alignment of 1 byte
+ return false;
+ }
+ }
+
+ if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) {
+ if ok.obligations.is_empty() {
+ create_err(
+ "the trait `DispatchFromDyn` may only be implemented \
+ for structs containing the field being coerced, \
+ ZST fields with 1 byte alignment, and nothing else",
+ )
+ .note(&format!(
+ "extra field `{}` of type `{}` is not allowed",
+ field.name, ty_a,
+ ))
+ .emit();
+
+ return false;
+ }
+ }
+
+ return true;
+ })
+ .collect::<Vec<_>>();
+
+ if coerced_fields.is_empty() {
+ create_err(
+ "the trait `DispatchFromDyn` may only be implemented \
+ for a coercion between structures with a single field \
+ being coerced, none found",
+ )
+ .emit();
+ } else if coerced_fields.len() > 1 {
+ create_err("implementing the `DispatchFromDyn` trait requires multiple coercions")
+ .note(
+ "the trait `DispatchFromDyn` may only be implemented \
+ for a coercion between structures with a single field \
+ being coerced",
+ )
+ .note(&format!(
+ "currently, {} fields need coercions: {}",
+ coerced_fields.len(),
+ coerced_fields
+ .iter()
+ .map(|field| {
+ format!(
+ "`{}` (`{}` to `{}`)",
+ field.name,
+ field.ty(tcx, substs_a),
+ field.ty(tcx, substs_b),
+ )
+ })
+ .collect::<Vec<_>>()
+ .join(", ")
+ ))
+ .emit();
+ } else {
+ let errors = traits::fully_solve_obligations(
+ &infcx,
+ coerced_fields.into_iter().map(|field| {
+ predicate_for_trait_def(
+ tcx,
+ param_env,
+ cause.clone(),
+ dispatch_from_dyn_trait,
+ 0,
+ field.ty(tcx, substs_a),
+ &[field.ty(tcx, substs_b).into()],
+ )
+ }),
+ );
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ }
+
+ // Finally, resolve all regions.
+ let outlives_env = OutlivesEnvironment::new(param_env);
+ infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
+ }
+ }
+ _ => {
+ create_err(
+ "the trait `DispatchFromDyn` may only be implemented \
+ for a coercion between structures",
+ )
+ .emit();
+ }
+ }
+}
+
+pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo {
+ debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
+
+ // this provider should only get invoked for local def-ids
+ let impl_did = impl_did.expect_local();
+ let span = tcx.def_span(impl_did);
+
+ 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 source = tcx.type_of(impl_did);
+ let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+ assert_eq!(trait_ref.def_id, coerce_unsized_trait);
+ let target = trait_ref.substs.type_at(1);
+ debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
+
+ let param_env = tcx.param_env(impl_did);
+ assert!(!source.has_escaping_bound_vars());
+
+ let err_info = CoerceUnsizedInfo { custom_kind: None };
+
+ debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
+
+ let infcx = tcx.infer_ctxt().build();
+ let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
+ let cause = ObligationCause::misc(span, impl_hir_id);
+ let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
+ mt_b: ty::TypeAndMut<'tcx>,
+ mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
+ if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) {
+ infcx
+ .err_ctxt()
+ .report_mismatched_types(
+ &cause,
+ mk_ptr(mt_b.ty),
+ target,
+ ty::error::TypeError::Mutability,
+ )
+ .emit();
+ }
+ (mt_a.ty, mt_b.ty, unsize_trait, None)
+ };
+ let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) {
+ (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
+ infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
+ let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
+ let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
+ check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
+ }
+
+ (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => {
+ let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
+ check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
+ }
+
+ (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)),
+
+ (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b))
+ if def_a.is_struct() && def_b.is_struct() =>
+ {
+ if def_a != def_b {
+ let source_path = tcx.def_path_str(def_a.did());
+ let target_path = tcx.def_path_str(def_b.did());
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0377,
+ "the trait `CoerceUnsized` may only be implemented \
+ for a coercion between structures with the same \
+ definition; expected `{}`, found `{}`",
+ source_path,
+ target_path
+ )
+ .emit();
+ return err_info;
+ }
+
+ // Here we are considering a case of converting
+ // `S<P0...Pn>` to S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
+ // which acts like a pointer to `U`, but carries along some extra data of type `T`:
+ //
+ // struct Foo<T, U> {
+ // extra: T,
+ // ptr: *mut U,
+ // }
+ //
+ // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
+ // to `Foo<T, [i32]>`. That impl would look like:
+ //
+ // impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
+ //
+ // Here `U = [i32; 3]` and `V = [i32]`. At runtime,
+ // when this coercion occurs, we would be changing the
+ // field `ptr` from a thin pointer of type `*mut [i32;
+ // 3]` to a fat pointer of type `*mut [i32]` (with
+ // extra data `3`). **The purpose of this check is to
+ // make sure that we know how to do this conversion.**
+ //
+ // To check if this impl is legal, we would walk down
+ // the fields of `Foo` and consider their types with
+ // both substitutes. We are looking to find that
+ // exactly one (non-phantom) field has changed its
+ // type, which we will expect to be the pointer that
+ // is becoming fat (we could probably generalize this
+ // to multiple thin pointers of the same type becoming
+ // fat, but we don't). In this case:
+ //
+ // - `extra` has type `T` before and type `T` after
+ // - `ptr` has type `*mut U` before and type `*mut V` after
+ //
+ // Since just one field changed, we would then check
+ // that `*mut U: CoerceUnsized<*mut V>` is implemented
+ // (in other words, that we know how to do this
+ // conversion). This will work out because `U:
+ // Unsize<V>`, and we have a builtin rule that `*mut
+ // U` can be coerced to `*mut V` if `U: Unsize<V>`.
+ let fields = &def_a.non_enum_variant().fields;
+ let diff_fields = fields
+ .iter()
+ .enumerate()
+ .filter_map(|(i, f)| {
+ let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
+
+ if tcx.type_of(f.did).is_phantom_data() {
+ // Ignore PhantomData fields
+ return None;
+ }
+
+ // Ignore fields that aren't changed; it may
+ // be that we could get away with subtyping or
+ // something more accepting, but we use
+ // equality because we want to be able to
+ // perform this check without computing
+ // variance where possible. (This is because
+ // we may have to evaluate constraint
+ // expressions in the course of execution.)
+ // See e.g., #41936.
+ if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) {
+ if ok.obligations.is_empty() {
+ return None;
+ }
+ }
+
+ // Collect up all fields that were significantly changed
+ // i.e., those that contain T in coerce_unsized T -> U
+ Some((i, a, b))
+ })
+ .collect::<Vec<_>>();
+
+ if diff_fields.is_empty() {
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0374,
+ "the trait `CoerceUnsized` may only be implemented \
+ for a coercion between structures with one field \
+ being coerced, none found"
+ )
+ .emit();
+ return err_info;
+ } else if diff_fields.len() > 1 {
+ let item = tcx.hir().expect_item(impl_did);
+ let span =
+ if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) = item.kind {
+ t.path.span
+ } else {
+ tcx.def_span(impl_did)
+ };
+
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0375,
+ "implementing the trait \
+ `CoerceUnsized` requires multiple \
+ coercions"
+ )
+ .note(
+ "`CoerceUnsized` may only be implemented for \
+ a coercion between structures with one field being coerced",
+ )
+ .note(&format!(
+ "currently, {} fields need coercions: {}",
+ diff_fields.len(),
+ diff_fields
+ .iter()
+ .map(|&(i, a, b)| { format!("`{}` (`{}` to `{}`)", fields[i].name, a, b) })
+ .collect::<Vec<_>>()
+ .join(", ")
+ ))
+ .span_label(span, "requires multiple coercions")
+ .emit();
+ return err_info;
+ }
+
+ let (i, a, b) = diff_fields[0];
+ let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
+ (a, b, coerce_unsized_trait, Some(kind))
+ }
+
+ _ => {
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0376,
+ "the trait `CoerceUnsized` may only be implemented \
+ for a coercion between structures"
+ )
+ .emit();
+ return err_info;
+ }
+ };
+
+ // Register an obligation for `A: Trait<B>`.
+ let cause = traits::ObligationCause::misc(span, impl_hir_id);
+ let predicate =
+ predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, source, &[target.into()]);
+ let errors = traits::fully_solve_obligation(&infcx, predicate);
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ }
+
+ // Finally, resolve all regions.
+ let outlives_env = OutlivesEnvironment::new(param_env);
+ infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
+
+ CoerceUnsizedInfo { custom_kind: kind }
+}
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 52aad636f..2890c149b 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -58,7 +58,7 @@ const ADD_ATTR: &str =
impl<'tcx> InherentCollect<'tcx> {
fn check_def_id(&mut self, item: &hir::Item<'_>, self_ty: Ty<'tcx>, def_id: DefId) {
- let impl_def_id = item.def_id;
+ let impl_def_id = item.owner_id;
if let Some(def_id) = def_id.as_local() {
// Add the implementation to the mapping from implementation to base
// type def ID, if there is a base type for this implementation and
@@ -89,7 +89,7 @@ impl<'tcx> InherentCollect<'tcx> {
for impl_item in items {
if !self
.tcx
- .has_attr(impl_item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl)
+ .has_attr(impl_item.id.owner_id.to_def_id(), sym::rustc_allow_incoherent_impl)
{
struct_span_err!(
self.tcx.sess,
@@ -105,7 +105,7 @@ impl<'tcx> InherentCollect<'tcx> {
}
if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) {
- self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
+ self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id.def_id);
} else {
bug!("unexpected self type: {:?}", self_ty);
}
@@ -135,7 +135,7 @@ impl<'tcx> InherentCollect<'tcx> {
for item in items {
if !self
.tcx
- .has_attr(item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl)
+ .has_attr(item.id.owner_id.to_def_id(), sym::rustc_allow_incoherent_impl)
{
struct_span_err!(
self.tcx.sess,
@@ -177,7 +177,7 @@ impl<'tcx> InherentCollect<'tcx> {
}
fn check_item(&mut self, id: hir::ItemId) {
- if !matches!(self.tcx.def_kind(id.def_id), DefKind::Impl) {
+ if !matches!(self.tcx.def_kind(id.owner_id), DefKind::Impl) {
return;
}
@@ -186,7 +186,7 @@ impl<'tcx> InherentCollect<'tcx> {
return;
};
- let self_ty = self.tcx.type_of(item.def_id);
+ let self_ty = self.tcx.type_of(item.owner_id);
match *self_ty.kind() {
ty::Adt(def, _) => {
self.check_def_id(item, self_ty, def.did());
@@ -220,7 +220,9 @@ impl<'tcx> InherentCollect<'tcx> {
| ty::Ref(..)
| ty::Never
| ty::FnPtr(_)
- | ty::Tuple(..) => self.check_primitive_impl(item.def_id, self_ty, items, ty.span),
+ | ty::Tuple(..) => {
+ self.check_primitive_impl(item.owner_id.def_id, self_ty, items, ty.span)
+ }
ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => {
let mut err = struct_span_err!(
self.tcx.sess,
@@ -241,7 +243,7 @@ impl<'tcx> InherentCollect<'tcx> {
| ty::Bound(..)
| ty::Placeholder(_)
| ty::Infer(_) => {
- bug!("unexpected impl self type of impl: {:?} {:?}", item.def_id, self_ty);
+ bug!("unexpected impl self type of impl: {:?} {:?}", item.owner_id, self_ty);
}
ty::Error(_) => {}
}
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
index 03e076bf5..972769eb1 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
@@ -58,6 +58,37 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
== item2.ident(self.tcx).normalize_to_macros_2_0()
}
+ fn check_for_duplicate_items_in_impl(&self, impl_: DefId) {
+ let impl_items = self.tcx.associated_items(impl_);
+
+ let mut seen_items = FxHashMap::default();
+ for impl_item in impl_items.in_definition_order() {
+ let span = self.tcx.def_span(impl_item.def_id);
+ let ident = impl_item.ident(self.tcx);
+
+ let norm_ident = ident.normalize_to_macros_2_0();
+ match seen_items.entry(norm_ident) {
+ Entry::Occupied(entry) => {
+ let former = entry.get();
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0592,
+ "duplicate definitions with name `{}`",
+ ident,
+ );
+ err.span_label(span, format!("duplicate definitions for `{}`", ident));
+ err.span_label(*former, format!("other definition for `{}`", ident));
+
+ err.emit();
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(span);
+ }
+ }
+ }
+ }
+
fn check_for_common_items_in_impls(
&self,
impl1: DefId,
@@ -117,29 +148,22 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
// inherent impls without warning.
SkipLeakCheck::Yes,
overlap_mode,
- |overlap| {
- self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
- false
- },
- || true,
- );
+ )
+ .map_or(true, |overlap| {
+ self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
+ false
+ });
}
fn check_item(&mut self, id: hir::ItemId) {
- let def_kind = self.tcx.def_kind(id.def_id);
+ let def_kind = self.tcx.def_kind(id.owner_id);
if !matches!(def_kind, DefKind::Enum | DefKind::Struct | DefKind::Trait | DefKind::Union) {
return;
}
- let impls = self.tcx.inherent_impls(id.def_id);
+ let impls = self.tcx.inherent_impls(id.owner_id);
- // If there is only one inherent impl block,
- // there is nothing to overlap check it with
- if impls.len() <= 1 {
- return;
- }
-
- let overlap_mode = OverlapMode::get(self.tcx, id.def_id.to_def_id());
+ let overlap_mode = OverlapMode::get(self.tcx, id.owner_id.to_def_id());
let impls_items = impls
.iter()
@@ -152,6 +176,8 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
const ALLOCATING_ALGO_THRESHOLD: usize = 500;
if impls.len() < ALLOCATING_ALGO_THRESHOLD {
for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() {
+ self.check_for_duplicate_items_in_impl(impl1_def_id);
+
for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] {
if self.impls_have_common_items(impl_items1, impl_items2) {
self.check_for_overlapping_inherent_impls(
@@ -290,6 +316,8 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
impl_blocks.sort_unstable();
for (i, &impl1_items_idx) in impl_blocks.iter().enumerate() {
let &(&impl1_def_id, impl_items1) = &impls_items[impl1_items_idx];
+ self.check_for_duplicate_items_in_impl(impl1_def_id);
+
for &impl2_items_idx in impl_blocks[(i + 1)..].iter() {
let &(&impl2_def_id, impl_items2) = &impls_items[impl2_items_idx];
if self.impls_have_common_items(impl_items1, impl_items2) {
diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index ae9ebe590..ae9ebe590 100644
--- a/compiler/rustc_typeck/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 1608550aa..bb45c3823 100644
--- a/compiler/rustc_typeck/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -2,10 +2,9 @@
//! crate or pertains to a type defined in this crate.
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, DelayDm};
use rustc_errors::{Diagnostic, ErrorGuaranteed};
use rustc_hir as hir;
-use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::IgnoreRegions;
@@ -43,7 +42,7 @@ fn do_orphan_check_impl<'tcx>(
) -> Result<(), ErrorGuaranteed> {
let trait_def_id = trait_ref.def_id;
- let item = tcx.hir().item(hir::ItemId { def_id });
+ let item = tcx.hir().expect_item(def_id);
let hir::ItemKind::Impl(ref impl_) = item.kind else {
bug!("{:?} is not an impl: {:?}", def_id, item);
};
@@ -102,7 +101,7 @@ fn do_orphan_check_impl<'tcx>(
span_bug!(sp, "opaque type not found, but `has_opaque_types` is set")
}
- match traits::orphan_check(tcx, item.def_id.to_def_id()) {
+ match traits::orphan_check(tcx, item.owner_id.to_def_id()) {
Ok(()) => {}
Err(err) => emit_orphan_check_error(
tcx,
@@ -229,12 +228,8 @@ fn emit_orphan_check_error<'tcx>(
"only traits defined in the current crate {msg}"
);
err.span_label(sp, "impl doesn't use only types from inside the current crate");
- for (ty, is_target_ty) in &tys {
- let mut ty = *ty;
- tcx.infer_ctxt().enter(|infcx| {
- // Remove the lifetimes unnecessary for this error.
- ty = infcx.freshen(ty);
- });
+ for &(mut ty, is_target_ty) in &tys {
+ ty = tcx.erase_regions(ty);
ty = match ty.kind() {
// Remove the type arguments from the output, as they are not relevant.
// You can think of this as the reverse of `resolve_vars_if_possible`.
@@ -264,7 +259,7 @@ fn emit_orphan_check_error<'tcx>(
};
let msg = format!("{} is not defined in the current crate{}", ty, postfix);
- if *is_target_ty {
+ 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);
} else {
@@ -417,30 +412,31 @@ fn lint_auto_trait_impl<'tcx>(
lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS,
tcx.hir().local_def_id_to_hir_id(impl_def_id),
tcx.def_span(impl_def_id),
- |err| {
- let item_span = tcx.def_span(self_type_did);
- let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
- let mut err = err.build(&format!(
+ DelayDm(|| {
+ format!(
"cross-crate traits with a default impl, like `{}`, \
should not be specialized",
tcx.def_path_str(trait_ref.def_id),
- ));
+ )
+ }),
+ |lint| {
+ let item_span = tcx.def_span(self_type_did);
+ let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
match arg {
ty::util::NotUniqueParam::DuplicateParam(arg) => {
- err.note(&format!("`{}` is mentioned multiple times", arg));
+ lint.note(&format!("`{}` is mentioned multiple times", arg));
}
ty::util::NotUniqueParam::NotParam(arg) => {
- err.note(&format!("`{}` is not a generic parameter", arg));
+ lint.note(&format!("`{}` is not a generic parameter", arg));
}
}
- err.span_note(
+ lint.span_note(
item_span,
&format!(
"try using the same sequence of generic parameters as the {} definition",
self_descr,
),
- );
- err.emit();
+ )
},
);
}
diff --git a/compiler/rustc_typeck/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
index e45fb5fe4..a34815b45 100644
--- a/compiler/rustc_typeck/src/coherence/unsafety.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
@@ -13,7 +13,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let item = tcx.hir().expect_item(def_id);
let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!() };
- if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) {
+ if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
let trait_def = tcx.trait_def(trait_ref.def_id);
let unsafe_attr =
impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
@@ -26,6 +26,12 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
"implementing the trait `{}` is not unsafe",
trait_ref.print_only_trait_path()
)
+ .span_suggestion_verbose(
+ item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)),
+ "remove `unsafe` from this trait implementation",
+ "",
+ rustc_errors::Applicability::MachineApplicable,
+ )
.emit();
}
@@ -37,6 +43,18 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
"the trait `{}` requires an `unsafe impl` declaration",
trait_ref.print_only_trait_path()
)
+ .note(format!(
+ "the trait `{}` enforces invariants that the compiler can't check. \
+ Review the trait documentation and make sure this implementation \
+ upholds those invariants before adding the `unsafe` keyword",
+ trait_ref.print_only_trait_path()
+ ))
+ .span_suggestion_verbose(
+ item.span.shrink_to_lo(),
+ "add `unsafe` to this trait implementation",
+ "unsafe ",
+ rustc_errors::Applicability::MaybeIncorrect,
+ )
.emit();
}
@@ -48,6 +66,18 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
"requires an `unsafe impl` declaration due to `#[{}]` attribute",
attr_name
)
+ .note(format!(
+ "the trait `{}` enforces invariants that the compiler can't check. \
+ Review the trait documentation and make sure this implementation \
+ upholds those invariants before adding the `unsafe` keyword",
+ trait_ref.print_only_trait_path()
+ ))
+ .span_suggestion_verbose(
+ item.span.shrink_to_lo(),
+ "add `unsafe` to this trait implementation",
+ "unsafe ",
+ rustc_errors::Applicability::MaybeIncorrect,
+ )
.emit();
}
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 45a5eca70..346d2e2fc 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -15,46 +15,41 @@
//! crate as a kind of pass. This should eventually be factored away.
use crate::astconv::AstConv;
-use crate::bounds::Bounds;
use crate::check::intrinsic::intrinsic_operation_unsafety;
-use crate::constrained_generic_params as cgp;
use crate::errors;
-use crate::middle::resolve_lifetime as rl;
use rustc_ast as ast;
use rustc_ast::{MetaItemKind, NestedMetaItem};
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
use rustc_hir as hir;
-use rustc_hir::def::{CtorKind, DefKind};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::def::CtorKind;
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::weak_lang_items;
-use rustc_hir::{GenericParamKind, HirId, Node};
+use rustc_hir::{GenericParamKind, Node};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::mono::Linkage;
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::util::Discr;
-use rustc_middle::ty::util::IntTypeExt;
+use rustc_middle::ty::util::{Discr, IntTypeExt};
+use rustc_middle::ty::ReprOptions;
use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, IsSuggestable, Ty, TyCtxt};
-use rustc_middle::ty::{ReprOptions, ToPredicate};
use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
use rustc_target::spec::{abi, SanitizerSet};
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use std::iter;
+mod generics_of;
mod item_bounds;
+mod lifetimes;
+mod predicates_of;
mod type_of;
-#[derive(Debug)]
-struct OnlySelfBounds(bool);
-
///////////////////////////////////////////////////////////////////////////
// Main entry point
@@ -63,19 +58,21 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
}
pub fn provide(providers: &mut Providers) {
+ lifetimes::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,
- generics_of,
- predicates_of,
+ generics_of: generics_of::generics_of,
+ predicates_of: predicates_of::predicates_of,
predicates_defined_on,
- explicit_predicates_of,
- super_predicates_of,
- super_predicates_that_define_assoc_type,
- trait_explicit_predicates_and_bounds,
- type_param_predicates,
+ explicit_predicates_of: predicates_of::explicit_predicates_of,
+ super_predicates_of: predicates_of::super_predicates_of,
+ super_predicates_that_define_assoc_type:
+ predicates_of::super_predicates_that_define_assoc_type,
+ trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
+ type_param_predicates: predicates_of::type_param_predicates,
trait_def,
adt_def,
fn_sig,
@@ -103,13 +100,12 @@ pub fn provide(providers: &mut Providers) {
/// It's also used for the bodies of items like structs where the body (the fields)
/// are just signatures.
///
-/// This is in contrast to [`FnCtxt`], which is used to type-check bodies of
+/// This is in contrast to `FnCtxt`, which is used to type-check bodies of
/// functions, closures, and `const`s -- anywhere that expressions and statements show up.
///
/// An important thing to note is that `ItemCtxt` does no inference -- it has no [`InferCtxt`] --
/// while `FnCtxt` does do inference.
///
-/// [`FnCtxt`]: crate::check::FnCtxt
/// [`InferCtxt`]: rustc_infer::infer::InferCtxt
///
/// # Trait predicates
@@ -430,7 +426,6 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
self,
- self.tcx,
span,
item_def_id,
item_segment,
@@ -449,8 +444,10 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
match self.node() {
hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => {
- let item =
- self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(self.hir_id()));
+ let item = self
+ .tcx
+ .hir()
+ .expect_item(self.tcx.hir().get_parent_item(self.hir_id()).def_id);
match &item.kind {
hir::ItemKind::Enum(_, generics)
| hir::ItemKind::Struct(_, generics)
@@ -571,164 +568,10 @@ fn get_new_lifetime_name<'tcx>(
(1..).flat_map(a_to_z_repeat_n).find(|lt| !existing_lifetimes.contains(lt.as_str())).unwrap()
}
-/// Returns the predicates defined on `item_def_id` of the form
-/// `X: Foo` where `X` is the type parameter `def_id`.
-#[instrument(level = "trace", skip(tcx))]
-fn type_param_predicates(
- tcx: TyCtxt<'_>,
- (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident),
-) -> ty::GenericPredicates<'_> {
- use rustc_hir::*;
-
- // In the AST, bounds can derive from two places. Either
- // written inline like `<T: Foo>` or in a where-clause like
- // `where T: Foo`.
-
- let param_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let param_owner = tcx.hir().ty_param_owner(def_id);
- let generics = tcx.generics_of(param_owner);
- let index = generics.param_def_id_to_index[&def_id.to_def_id()];
- let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id));
-
- // Don't look for bounds where the type parameter isn't in scope.
- let parent = if item_def_id == param_owner.to_def_id() {
- None
- } else {
- tcx.generics_of(item_def_id).parent
- };
-
- let mut result = parent
- .map(|parent| {
- let icx = ItemCtxt::new(tcx, parent);
- icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name)
- })
- .unwrap_or_default();
- let mut extend = None;
-
- let item_hir_id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local());
- let ast_generics = match tcx.hir().get(item_hir_id) {
- Node::TraitItem(item) => &item.generics,
-
- Node::ImplItem(item) => &item.generics,
-
- Node::Item(item) => {
- match item.kind {
- ItemKind::Fn(.., ref generics, _)
- | ItemKind::Impl(hir::Impl { ref generics, .. })
- | ItemKind::TyAlias(_, ref generics)
- | ItemKind::OpaqueTy(OpaqueTy {
- ref generics,
- origin: hir::OpaqueTyOrigin::TyAlias,
- ..
- })
- | ItemKind::Enum(_, ref generics)
- | ItemKind::Struct(_, ref generics)
- | ItemKind::Union(_, ref generics) => generics,
- ItemKind::Trait(_, _, ref generics, ..) => {
- // Implied `Self: Trait` and supertrait bounds.
- if param_id == item_hir_id {
- let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
- extend =
- Some((identity_trait_ref.without_const().to_predicate(tcx), item.span));
- }
- generics
- }
- _ => return result,
- }
- }
-
- Node::ForeignItem(item) => match item.kind {
- ForeignItemKind::Fn(_, _, ref generics) => generics,
- _ => return result,
- },
-
- _ => return result,
- };
-
- let icx = ItemCtxt::new(tcx, item_def_id);
- let extra_predicates = extend.into_iter().chain(
- icx.type_parameter_bounds_in_generics(
- ast_generics,
- param_id,
- ty,
- OnlySelfBounds(true),
- Some(assoc_name),
- )
- .into_iter()
- .filter(|(predicate, _)| match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(data) => data.self_ty().is_param(index),
- _ => false,
- }),
- );
- result.predicates =
- tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(extra_predicates));
- result
-}
-
-impl<'tcx> ItemCtxt<'tcx> {
- /// Finds bounds from `hir::Generics`. This requires scanning through the
- /// AST. We do this to avoid having to convert *all* the bounds, which
- /// would create artificial cycles. Instead, we can only convert the
- /// bounds for a type parameter `X` if `X::Foo` is used.
- #[instrument(level = "trace", skip(self, ast_generics))]
- fn type_parameter_bounds_in_generics(
- &self,
- ast_generics: &'tcx hir::Generics<'tcx>,
- param_id: hir::HirId,
- ty: Ty<'tcx>,
- only_self_bounds: OnlySelfBounds,
- assoc_name: Option<Ident>,
- ) -> Vec<(ty::Predicate<'tcx>, Span)> {
- let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
- trace!(?param_def_id);
- ast_generics
- .predicates
- .iter()
- .filter_map(|wp| match *wp {
- hir::WherePredicate::BoundPredicate(ref bp) => Some(bp),
- _ => None,
- })
- .flat_map(|bp| {
- let bt = if bp.is_param_bound(param_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.bounded_ty.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()
- }
-
- #[instrument(level = "trace", skip(self))]
- fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
- match b {
- 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)
- } else {
- false
- }
- }
- _ => false,
- }
- }
-}
-
fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
let it = tcx.hir().item(item_id);
debug!("convert: item {} with id {}", it.ident, it.hir_id());
- let def_id = item_id.def_id;
+ let def_id = item_id.owner_id.def_id;
match it.kind {
// These don't define types.
@@ -740,11 +583,11 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
hir::ItemKind::ForeignMod { items, .. } => {
for item in items {
let item = tcx.hir().foreign_item(item.id);
- tcx.ensure().generics_of(item.def_id);
- tcx.ensure().type_of(item.def_id);
- tcx.ensure().predicates_of(item.def_id);
+ tcx.ensure().generics_of(item.owner_id);
+ tcx.ensure().type_of(item.owner_id);
+ tcx.ensure().predicates_of(item.owner_id);
match item.kind {
- hir::ForeignItemKind::Fn(..) => tcx.ensure().fn_sig(item.def_id),
+ hir::ForeignItemKind::Fn(..) => tcx.ensure().fn_sig(item.owner_id),
hir::ForeignItemKind::Static(..) => {
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_foreign_item(item);
@@ -840,20 +683,21 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
let trait_item = tcx.hir().trait_item(trait_item_id);
- tcx.ensure().generics_of(trait_item_id.def_id);
+ let def_id = trait_item_id.owner_id;
+ tcx.ensure().generics_of(def_id);
match trait_item.kind {
hir::TraitItemKind::Fn(..) => {
- tcx.ensure().type_of(trait_item_id.def_id);
- tcx.ensure().fn_sig(trait_item_id.def_id);
+ tcx.ensure().type_of(def_id);
+ tcx.ensure().fn_sig(def_id);
}
hir::TraitItemKind::Const(.., Some(_)) => {
- tcx.ensure().type_of(trait_item_id.def_id);
+ tcx.ensure().type_of(def_id);
}
hir::TraitItemKind::Const(hir_ty, _) => {
- tcx.ensure().type_of(trait_item_id.def_id);
+ tcx.ensure().type_of(def_id);
// Account for `const C: _;`.
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_trait_item(trait_item);
@@ -863,8 +707,8 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
}
hir::TraitItemKind::Type(_, Some(_)) => {
- tcx.ensure().item_bounds(trait_item_id.def_id);
- tcx.ensure().type_of(trait_item_id.def_id);
+ tcx.ensure().item_bounds(def_id);
+ tcx.ensure().type_of(def_id);
// Account for `type T = _;`.
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_trait_item(trait_item);
@@ -872,7 +716,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
}
hir::TraitItemKind::Type(_, None) => {
- tcx.ensure().item_bounds(trait_item_id.def_id);
+ tcx.ensure().item_bounds(def_id);
// #74612: Visit and try to find bad placeholders
// even if there is no concrete type.
let mut visitor = HirPlaceholderCollector::default();
@@ -882,11 +726,11 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
}
};
- tcx.ensure().predicates_of(trait_item_id.def_id);
+ tcx.ensure().predicates_of(def_id);
}
fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
- let def_id = impl_item_id.def_id;
+ let def_id = impl_item_id.owner_id;
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
@@ -895,7 +739,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
hir::ImplItemKind::Fn(..) => {
tcx.ensure().fn_sig(def_id);
}
- hir::ImplItemKind::TyAlias(_) => {
+ hir::ImplItemKind::Type(_) => {
// Account for `type T = _;`
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_impl_item(impl_item);
@@ -1095,96 +939,6 @@ fn adt_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AdtDef<'tcx> {
tcx.alloc_adt_def(def_id.to_def_id(), kind, variants, repr)
}
-/// Ensures that the super-predicates of the trait with a `DefId`
-/// of `trait_def_id` are converted and stored. This also ensures that
-/// the transitive super-predicates are converted.
-fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredicates<'_> {
- debug!("super_predicates(trait_def_id={:?})", trait_def_id);
- tcx.super_predicates_that_define_assoc_type((trait_def_id, None))
-}
-
-/// Ensures that the super-predicates of the trait with a `DefId`
-/// of `trait_def_id` are converted and stored. This also ensures that
-/// the transitive super-predicates are converted.
-fn super_predicates_that_define_assoc_type(
- tcx: TyCtxt<'_>,
- (trait_def_id, assoc_name): (DefId, Option<Ident>),
-) -> ty::GenericPredicates<'_> {
- debug!(
- "super_predicates_that_define_assoc_type(trait_def_id={:?}, assoc_name={:?})",
- trait_def_id, assoc_name
- );
- if trait_def_id.is_local() {
- debug!("super_predicates_that_define_assoc_type: local trait_def_id={:?}", trait_def_id);
- let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local());
-
- let Node::Item(item) = tcx.hir().get(trait_hir_id) else {
- bug!("trait_node_id {} is not an item", trait_hir_id);
- };
-
- let (generics, bounds) = match item.kind {
- hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits),
- hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits),
- _ => span_bug!(item.span, "super_predicates invoked on non-trait"),
- };
-
- let icx = ItemCtxt::new(tcx, trait_def_id);
-
- // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
- let self_param_ty = tcx.types.self_param;
- let superbounds1 = if let Some(assoc_name) = assoc_name {
- <dyn AstConv<'_>>::compute_bounds_that_match_assoc_type(
- &icx,
- self_param_ty,
- bounds,
- assoc_name,
- )
- } else {
- <dyn AstConv<'_>>::compute_bounds(&icx, self_param_ty, bounds)
- };
-
- let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
-
- // Convert any explicit superbounds in the where-clause,
- // e.g., `trait Foo where Self: Bar`.
- // In the case of trait aliases, however, we include all bounds in the where-clause,
- // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
- // as one of its "superpredicates".
- let is_trait_alias = tcx.is_trait_alias(trait_def_id);
- let superbounds2 = icx.type_parameter_bounds_in_generics(
- generics,
- item.hir_id(),
- self_param_ty,
- OnlySelfBounds(!is_trait_alias),
- assoc_name,
- );
-
- // Combine the two lists to form the complete set of superbounds:
- let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
- debug!(?superbounds);
-
- // Now require that immediate supertraits are converted,
- // which will, in turn, reach indirect supertraits.
- if assoc_name.is_none() {
- // Now require that immediate supertraits are converted,
- // which will, in turn, reach indirect supertraits.
- for &(pred, span) in superbounds {
- debug!("superbound: {:?}", pred);
- if let ty::PredicateKind::Trait(bound) = pred.kind().skip_binder() {
- tcx.at(span).super_predicates_of(bound.def_id());
- }
- }
- }
-
- ty::GenericPredicates { parent: None, predicates: superbounds }
- } else {
- // if `assoc_name` is None, then the query should've been redirected to an
- // external provider
- assert!(assoc_name.is_some());
- tcx.super_predicates_of(trait_def_id)
- }
-}
-
fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
let item = tcx.hir().expect_item(def_id.expect_local());
@@ -1256,7 +1010,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
match item {
Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => {
- if !tcx.impl_defaultness(item.id.def_id).has_value() {
+ if !tcx.impl_defaultness(item.id.owner_id).has_value() {
tcx.sess
.struct_span_err(
item.span,
@@ -1326,475 +1080,6 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
)
}
-fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<Span> {
- struct LateBoundRegionsDetector<'tcx> {
- tcx: TyCtxt<'tcx>,
- outer_index: ty::DebruijnIndex,
- has_late_bound_regions: Option<Span>,
- }
-
- impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
- fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
- if self.has_late_bound_regions.is_some() {
- return;
- }
- match ty.kind {
- hir::TyKind::BareFn(..) => {
- self.outer_index.shift_in(1);
- intravisit::walk_ty(self, ty);
- self.outer_index.shift_out(1);
- }
- _ => intravisit::walk_ty(self, ty),
- }
- }
-
- fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) {
- if self.has_late_bound_regions.is_some() {
- return;
- }
- self.outer_index.shift_in(1);
- intravisit::walk_poly_trait_ref(self, tr);
- self.outer_index.shift_out(1);
- }
-
- fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
- if self.has_late_bound_regions.is_some() {
- return;
- }
-
- match self.tcx.named_region(lt.hir_id) {
- Some(rl::Region::Static | rl::Region::EarlyBound(..)) => {}
- Some(rl::Region::LateBound(debruijn, _, _)) if debruijn < self.outer_index => {}
- Some(rl::Region::LateBound(..) | rl::Region::Free(..)) | None => {
- self.has_late_bound_regions = Some(lt.span);
- }
- }
- }
- }
-
- fn has_late_bound_regions<'tcx>(
- tcx: TyCtxt<'tcx>,
- generics: &'tcx hir::Generics<'tcx>,
- decl: &'tcx hir::FnDecl<'tcx>,
- ) -> Option<Span> {
- let mut visitor = LateBoundRegionsDetector {
- tcx,
- outer_index: ty::INNERMOST,
- has_late_bound_regions: None,
- };
- for param in generics.params {
- if let GenericParamKind::Lifetime { .. } = param.kind {
- if tcx.is_late_bound(param.hir_id) {
- return Some(param.span);
- }
- }
- }
- visitor.visit_fn_decl(decl);
- visitor.has_late_bound_regions
- }
-
- match node {
- Node::TraitItem(item) => match item.kind {
- hir::TraitItemKind::Fn(ref sig, _) => {
- has_late_bound_regions(tcx, &item.generics, sig.decl)
- }
- _ => None,
- },
- Node::ImplItem(item) => match item.kind {
- hir::ImplItemKind::Fn(ref sig, _) => {
- has_late_bound_regions(tcx, &item.generics, sig.decl)
- }
- _ => None,
- },
- Node::ForeignItem(item) => match item.kind {
- hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
- has_late_bound_regions(tcx, generics, fn_decl)
- }
- _ => None,
- },
- Node::Item(item) => match item.kind {
- hir::ItemKind::Fn(ref sig, .., ref generics, _) => {
- has_late_bound_regions(tcx, generics, sig.decl)
- }
- _ => None,
- },
- _ => None,
- }
-}
-
-struct AnonConstInParamTyDetector {
- in_param_ty: bool,
- found_anon_const_in_param_ty: bool,
- ct: HirId,
-}
-
-impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
- fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
- if let GenericParamKind::Const { ty, default: _ } = p.kind {
- let prev = self.in_param_ty;
- self.in_param_ty = true;
- self.visit_ty(ty);
- self.in_param_ty = prev;
- }
- }
-
- fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
- if self.in_param_ty && self.ct == c.hir_id {
- self.found_anon_const_in_param_ty = true;
- } else {
- intravisit::walk_anon_const(self, c)
- }
- }
-}
-
-fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
- use rustc_hir::*;
-
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-
- let node = tcx.hir().get(hir_id);
- let parent_def_id = match node {
- Node::ImplItem(_)
- | Node::TraitItem(_)
- | Node::Variant(_)
- | Node::Ctor(..)
- | Node::Field(_) => {
- let parent_id = tcx.hir().get_parent_item(hir_id);
- Some(parent_id.to_def_id())
- }
- // FIXME(#43408) always enable this once `lazy_normalization` is
- // stable enough and does not need a feature gate anymore.
- Node::AnonConst(_) => {
- let parent_def_id = tcx.hir().get_parent_item(hir_id);
-
- let mut in_param_ty = false;
- for (_parent, node) in tcx.hir().parent_iter(hir_id) {
- if let Some(generics) = node.generics() {
- let mut visitor = AnonConstInParamTyDetector {
- in_param_ty: false,
- found_anon_const_in_param_ty: false,
- ct: hir_id,
- };
-
- visitor.visit_generics(generics);
- in_param_ty = visitor.found_anon_const_in_param_ty;
- break;
- }
- }
-
- if in_param_ty {
- // We do not allow generic parameters in anon consts if we are inside
- // 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_hir_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 = { .. }>;
- // ^^^ ^ ^^^^^^ def id of this anon const
- // ^ ^ param_id
- // ^ parent_def_id
- //
- // then we only want to return generics for params to the left of `N`. If we don't do that we
- // end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, substs: [N#0])`.
- //
- // This causes ICEs (#86580) when building the substs for Foo in `fn foo() -> Foo { .. }` as
- // we substitute the defaults with the partially built substs when we build the substs. Subst'ing
- // the `N#0` on the unevaluated const indexes into the empty substs we're in the process of building.
- //
- // We fix this by having this function return the parent's generics ourselves and truncating the
- // generics to only include non-forward declared params (with the exception of the `Self` ty)
- //
- // For the above code example that means we want `substs: []`
- // For the following struct def we want `substs: [N#0]` when generics_of is called on
- // the def id of the `{ N + 1 }` anon const
- // struct Foo<const N: usize, const M: usize = { N + 1 }>;
- //
- // This has some implications for how we get the predicates available to the anon const
- // see `explicit_predicates_of` for more information on this
- let generics = tcx.generics_of(parent_def_id.to_def_id());
- let param_def = tcx.hir().local_def_id(param_id).to_def_id();
- let param_def_idx = generics.param_def_id_to_index[&param_def];
- // In the above example this would be .params[..N#0]
- let params = generics.params[..param_def_idx as usize].to_owned();
- let param_def_id_to_index =
- params.iter().map(|param| (param.def_id, param.index)).collect();
-
- return ty::Generics {
- // we set the parent of these generics to be our parent's parent so that we
- // dont end up with substs: [N, M, N] for the const default on a struct like this:
- // struct Foo<const N: usize, const M: usize = { ... }>;
- parent: generics.parent,
- parent_count: generics.parent_count,
- params,
- param_def_id_to_index,
- has_self: generics.has_self,
- has_late_bound_regions: generics.has_late_bound_regions,
- };
- }
-
- // 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(tcx.hir().get_parent_node(hir_id));
- match parent_node {
- // HACK(eddyb) this provides the correct generics for repeat
- // expressions' count (i.e. `N` in `[x; N]`), and explicit
- // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
- // as they shouldn't be able to cause query cycle errors.
- Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
- if constant.hir_id() == hir_id =>
- {
- Some(parent_def_id.to_def_id())
- }
- Node::Variant(Variant { disr_expr: Some(ref 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))
- }
- // Exclude `GlobalAsm` here which cannot have generics.
- Node::Expr(&Expr { kind: ExprKind::InlineAsm(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,
- }) =>
- {
- Some(parent_def_id.to_def_id())
- }
- _ => None,
- }
- }
- }
- Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
- Some(tcx.typeck_root_def_id(def_id))
- }
- Node::Item(item) => match item.kind {
- ItemKind::OpaqueTy(hir::OpaqueTy {
- origin:
- hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
- in_trait,
- ..
- }) => {
- if in_trait {
- assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn))
- } else {
- assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn))
- }
- Some(fn_def_id.to_def_id())
- }
- ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
- let parent_id = tcx.hir().get_parent_item(hir_id);
- assert_ne!(parent_id, CRATE_DEF_ID);
- debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
- // Opaque types are always nested within another item, and
- // inherit the generics of the item.
- Some(parent_id.to_def_id())
- }
- _ => None,
- },
- _ => None,
- };
-
- enum Defaults {
- Allowed,
- // See #36887
- FutureCompatDisallowed,
- Deny,
- }
-
- let no_generics = hir::Generics::empty();
- let ast_generics = node.generics().unwrap_or(&no_generics);
- let (opt_self, allow_defaults) = match node {
- Node::Item(item) => {
- match item.kind {
- ItemKind::Trait(..) | ItemKind::TraitAlias(..) => {
- // Add in the self type parameter.
- //
- // Something of a hack: use the node id for the trait, also as
- // the node id for the Self type parameter.
- let opt_self = Some(ty::GenericParamDef {
- index: 0,
- name: kw::SelfUpper,
- def_id,
- pure_wrt_drop: false,
- kind: ty::GenericParamDefKind::Type {
- has_default: false,
- synthetic: false,
- },
- });
-
- (opt_self, Defaults::Allowed)
- }
- ItemKind::TyAlias(..)
- | ItemKind::Enum(..)
- | ItemKind::Struct(..)
- | ItemKind::OpaqueTy(..)
- | ItemKind::Union(..) => (None, Defaults::Allowed),
- _ => (None, Defaults::FutureCompatDisallowed),
- }
- }
-
- // GATs
- Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => {
- (None, Defaults::Deny)
- }
- Node::ImplItem(item) if matches!(item.kind, ImplItemKind::TyAlias(..)) => {
- (None, Defaults::Deny)
- }
-
- _ => (None, Defaults::FutureCompatDisallowed),
- };
-
- let has_self = opt_self.is_some();
- let mut parent_has_self = false;
- let mut own_start = has_self as u32;
- let parent_count = parent_def_id.map_or(0, |def_id| {
- let generics = tcx.generics_of(def_id);
- assert!(!has_self);
- parent_has_self = generics.has_self;
- own_start = generics.count() as u32;
- generics.parent_count + generics.params.len()
- });
-
- let mut params: Vec<_> = Vec::with_capacity(ast_generics.params.len() + has_self as usize);
-
- if let Some(opt_self) = opt_self {
- params.push(opt_self);
- }
-
- let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
- params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
- name: param.name.ident().name,
- index: own_start + i as u32,
- def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
- pure_wrt_drop: param.pure_wrt_drop,
- kind: ty::GenericParamDefKind::Lifetime,
- }));
-
- // Now create the real type and const parameters.
- let type_start = own_start - has_self as u32 + params.len() as u32;
- let mut i = 0;
-
- const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
- `struct`, `enum`, `type`, or `trait` definitions";
-
- params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => None,
- GenericParamKind::Type { ref default, synthetic, .. } => {
- if default.is_some() {
- match allow_defaults {
- Defaults::Allowed => {}
- Defaults::FutureCompatDisallowed
- if tcx.features().default_type_parameter_fallback => {}
- Defaults::FutureCompatDisallowed => {
- tcx.struct_span_lint_hir(
- lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
- param.hir_id,
- param.span,
- |lint| {
- lint.build(TYPE_DEFAULT_NOT_ALLOWED).emit();
- },
- );
- }
- Defaults::Deny => {
- tcx.sess.span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED);
- }
- }
- }
-
- let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic };
-
- let param_def = ty::GenericParamDef {
- index: type_start + i as u32,
- name: param.name.ident().name,
- def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
- pure_wrt_drop: param.pure_wrt_drop,
- kind,
- };
- i += 1;
- Some(param_def)
- }
- GenericParamKind::Const { default, .. } => {
- if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() {
- tcx.sess.span_err(
- param.span,
- "defaults for const parameters are only allowed in \
- `struct`, `enum`, `type`, or `trait` definitions",
- );
- }
-
- let param_def = ty::GenericParamDef {
- index: type_start + i as u32,
- name: param.name.ident().name,
- def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
- pure_wrt_drop: param.pure_wrt_drop,
- kind: ty::GenericParamDefKind::Const { has_default: default.is_some() },
- };
- i += 1;
- Some(param_def)
- }
- }));
-
- // provide junk type parameter defs - the only place that
- // cares about anything but the length is instantiation,
- // and we don't do that for closures.
- if let Node::Expr(&hir::Expr {
- kind: hir::ExprKind::Closure(hir::Closure { movability: gen, .. }),
- ..
- }) = node
- {
- let dummy_args = if gen.is_some() {
- &["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
- } else {
- &["<closure_kind>", "<closure_signature>", "<upvars>"][..]
- };
-
- params.extend(dummy_args.iter().enumerate().map(|(i, &arg)| ty::GenericParamDef {
- index: type_start + i as u32,
- name: Symbol::intern(arg),
- def_id,
- pure_wrt_drop: false,
- kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
- }));
- }
-
- // provide junk type parameter defs for const blocks.
- if let Node::AnonConst(_) = node {
- let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
- if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
- params.push(ty::GenericParamDef {
- index: type_start,
- name: Symbol::intern("<const_ty>"),
- def_id,
- pure_wrt_drop: false,
- kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
- });
- }
- }
-
- let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
-
- ty::Generics {
- parent: parent_def_id,
- parent_count,
- params,
- param_def_id_to_index,
- has_self: has_self || parent_has_self,
- has_late_bound_regions: has_late_bound_regions(tcx, node),
- }
-}
-
fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool {
generic_args.iter().any(|arg| match arg {
hir::GenericArg::Type(ty) => is_suggestable_infer_ty(ty),
@@ -1858,7 +1143,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
}
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
- // Do not try to inference the return type for a impl method coming from a trait
+ // Do not try to infer the return type for a impl method coming from a trait
if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
tcx.hir().get(tcx.hir().get_parent_node(hir_id))
&& i.of_trait.is_some()
@@ -2001,15 +1286,46 @@ fn infer_return_ty_for_fn_sig<'tcx>(
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
let icx = ItemCtxt::new(tcx, def_id);
- match tcx.hir().expect_item(def_id.expect_local()).kind {
+ let item = tcx.hir().expect_item(def_id.expect_local());
+ match item.kind {
hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id);
- <dyn AstConv<'_>>::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
+ <dyn AstConv<'_>>::instantiate_mono_trait_ref(
+ &icx,
+ ast_trait_ref,
+ selfty,
+ check_impl_constness(tcx, impl_.constness, ast_trait_ref),
+ )
}),
_ => bug!(),
}
}
+fn check_impl_constness(
+ tcx: TyCtxt<'_>,
+ constness: hir::Constness,
+ ast_trait_ref: &hir::TraitRef<'_>,
+) -> ty::BoundConstness {
+ match constness {
+ hir::Constness::Const => {
+ if let Some(trait_def_id) = ast_trait_ref.trait_def_id() && !tcx.has_attr(trait_def_id, sym::const_trait) {
+ let trait_name = tcx.item_name(trait_def_id).to_string();
+ tcx.sess.emit_err(errors::ConstImplForNonConstTrait {
+ trait_ref_span: ast_trait_ref.path.span,
+ trait_name,
+ local_trait_span: trait_def_id.as_local().map(|_| tcx.def_span(trait_def_id).shrink_to_lo()),
+ marking: (),
+ adding: (),
+ });
+ ty::BoundConstness::NotConst
+ } else {
+ ty::BoundConstness::ConstIfConst
+ }
+ },
+ hir::Constness::NotConst => ty::BoundConstness::NotConst,
+ }
+}
+
fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity {
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
let item = tcx.hir().expect_item(def_id.expect_local());
@@ -2091,451 +1407,6 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate
result
}
-/// 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.
-fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
- let mut result = tcx.predicates_defined_on(def_id);
-
- if tcx.is_trait(def_id) {
- // For traits, add `Self: Trait` predicate. This is
- // not part of the predicates that a user writes, but it
- // is something that one must prove in order to invoke a
- // method or project an associated type.
- //
- // In the chalk setup, this predicate is not part of the
- // "predicates" for a trait item. But it is useful in
- // rustc because if you directly (e.g.) invoke a trait
- // method like `Trait::method(...)`, you must naturally
- // prove that the trait applies to the types that were
- // used, and adding the predicate into this list ensures
- // that this is done.
- //
- // We use a DUMMY_SP here as a way to signal trait bounds that come
- // from the trait itself that *shouldn't* be shown as the source of
- // an obligation and instead be skipped. Otherwise we'd use
- // `tcx.def_span(def_id);`
-
- let constness = if tcx.has_attr(def_id, sym::const_trait) {
- ty::BoundConstness::ConstIfConst
- } else {
- ty::BoundConstness::NotConst
- };
-
- let span = rustc_span::DUMMY_SP;
- result.predicates =
- tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
- ty::TraitRef::identity(tcx, def_id).with_constness(constness).to_predicate(tcx),
- span,
- ))));
- }
- debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
- result
-}
-
-/// Returns a list of user-specified type predicates for the definition with ID `def_id`.
-/// N.B., this does not include any implied/inferred constraints.
-#[instrument(level = "trace", skip(tcx), ret)]
-fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
- use rustc_hir::*;
-
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let node = tcx.hir().get(hir_id);
-
- let mut is_trait = None;
- let mut is_default_impl_trait = None;
-
- let icx = ItemCtxt::new(tcx, def_id);
-
- const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
-
- // We use an `IndexSet` to preserves order of insertion.
- // Preserving the order of insertion is important here so as not to break UI tests.
- let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
-
- let ast_generics = match node {
- Node::TraitItem(item) => item.generics,
-
- Node::ImplItem(item) => item.generics,
-
- Node::Item(item) => {
- match item.kind {
- ItemKind::Impl(ref impl_) => {
- if impl_.defaultness.is_default() {
- is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
- }
- &impl_.generics
- }
- ItemKind::Fn(.., ref generics, _)
- | ItemKind::TyAlias(_, ref generics)
- | ItemKind::Enum(_, ref generics)
- | ItemKind::Struct(_, ref generics)
- | ItemKind::Union(_, ref generics) => *generics,
-
- ItemKind::Trait(_, _, ref generics, ..) => {
- is_trait = Some(ty::TraitRef::identity(tcx, def_id));
- *generics
- }
- ItemKind::TraitAlias(ref generics, _) => {
- is_trait = Some(ty::TraitRef::identity(tcx, def_id));
- *generics
- }
- ItemKind::OpaqueTy(OpaqueTy {
- origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
- ..
- }) => {
- // return-position impl trait
- //
- // We don't inherit predicates from the parent here:
- // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
- // then the return type is `f::<'static, T>::{{opaque}}`.
- //
- // If we inherited the predicates of `f` then we would
- // require that `T: 'static` to show that the return
- // type is well-formed.
- //
- // The only way to have something with this opaque type
- // is from the return type of the containing function,
- // which will ensure that the function's predicates
- // hold.
- return ty::GenericPredicates { parent: None, predicates: &[] };
- }
- ItemKind::OpaqueTy(OpaqueTy {
- ref generics,
- origin: hir::OpaqueTyOrigin::TyAlias,
- ..
- }) => {
- // type-alias impl trait
- generics
- }
-
- _ => NO_GENERICS,
- }
- }
-
- Node::ForeignItem(item) => match item.kind {
- ForeignItemKind::Static(..) => NO_GENERICS,
- ForeignItemKind::Fn(_, _, ref generics) => *generics,
- ForeignItemKind::Type => NO_GENERICS,
- },
-
- _ => NO_GENERICS,
- };
-
- let generics = tcx.generics_of(def_id);
- let parent_count = generics.parent_count as u32;
- let has_own_self = generics.has_self && parent_count == 0;
-
- // 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.super_predicates_of(def_id).predicates.iter().cloned());
- }
-
- // In default impls, we can assume that the self type implements
- // the trait. So in:
- //
- // default impl Foo for Bar { .. }
- //
- // we add a default where clause `Foo: Bar`. We do a similar thing for traits
- // (see below). Recall that a default impl is not itself an impl, but rather a
- // set of defaults that can be incorporated into another impl.
- if let Some(trait_ref) = is_default_impl_trait {
- predicates.insert((trait_ref.without_const().to_predicate(tcx), tcx.def_span(def_id)));
- }
-
- // Collect the region predicates that were declared inline as
- // well. In the case of parameters declared on a fn or method, we
- // have to be careful to only iterate over early-bound regions.
- let mut index = parent_count
- + has_own_self as u32
- + early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32;
-
- trace!(?predicates);
- trace!(?ast_generics);
-
- // Collect the predicates that were written inline by the user on each
- // type parameter (e.g., `<T: Foo>`).
- for param in ast_generics.params {
- match param.kind {
- // We already dealt with early bound lifetimes above.
- GenericParamKind::Lifetime { .. } => (),
- GenericParamKind::Type { .. } => {
- let name = param.name.ident().name;
- let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
- index += 1;
-
- let mut bounds = Bounds::default();
- // Params are implicitly sized unless a `?Sized` bound is found
- <dyn AstConv<'_>>::add_implicitly_sized(
- &icx,
- &mut bounds,
- &[],
- Some((param.hir_id, ast_generics.predicates)),
- param.span,
- );
- trace!(?bounds);
- predicates.extend(bounds.predicates(tcx, param_ty));
- trace!(?predicates);
- }
- GenericParamKind::Const { .. } => {
- // Bounds on const parameters are currently not possible.
- index += 1;
- }
- }
- }
-
- trace!(?predicates);
- // Add in the bounds that appear in the where-clause.
- for predicate in ast_generics.predicates {
- match predicate {
- hir::WherePredicate::BoundPredicate(bound_pred) => {
- let ty = icx.to_ty(bound_pred.bounded_ty);
- let bound_vars = icx.tcx.late_bound_vars(bound_pred.bounded_ty.hir_id);
-
- // Keep the type around in a dummy predicate, in case of no bounds.
- // That way, `where Ty:` is not a complete noop (see #53696) and `Ty`
- // is still checked for WF.
- if bound_pred.bounds.is_empty() {
- if let ty::Param(_) = ty.kind() {
- // This is a `where T:`, which can be in the HIR from the
- // transformation that moves `?Sized` to `T`'s declaration.
- // We can skip the predicate because type parameters are
- // trivially WF, but also we *should*, to avoid exposing
- // users who never wrote `where Type:,` themselves, to
- // compiler/tooling bugs from not handling WF predicates.
- } else {
- let span = bound_pred.bounded_ty.span;
- let predicate = ty::Binder::bind_with_vars(
- ty::PredicateKind::WellFormed(ty.into()),
- bound_vars,
- );
- predicates.insert((predicate.to_predicate(tcx), span));
- }
- }
-
- let mut bounds = Bounds::default();
- <dyn AstConv<'_>>::add_bounds(
- &icx,
- ty,
- bound_pred.bounds.iter(),
- &mut bounds,
- bound_vars,
- );
- predicates.extend(bounds.predicates(tcx, ty));
- }
-
- hir::WherePredicate::RegionPredicate(region_pred) => {
- let r1 = <dyn AstConv<'_>>::ast_region_to_region(&icx, &region_pred.lifetime, None);
- predicates.extend(region_pred.bounds.iter().map(|bound| {
- let (r2, span) = match bound {
- hir::GenericBound::Outlives(lt) => {
- (<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.span)
- }
- _ => bug!(),
- };
- let pred = ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
- ty::OutlivesPredicate(r1, r2),
- ))
- .to_predicate(icx.tcx);
-
- (pred, span)
- }))
- }
-
- hir::WherePredicate::EqPredicate(..) => {
- // FIXME(#20041)
- }
- }
- }
-
- if tcx.features().generic_const_exprs {
- predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
- }
-
- let mut predicates: Vec<_> = predicates.into_iter().collect();
-
- // Subtle: before we store the predicates into the tcx, we
- // sort them so that predicates like `T: Foo<Item=U>` come
- // before uses of `U`. This avoids false ambiguity errors
- // in trait checking. See `setup_constraining_predicates`
- // for details.
- if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
- let self_ty = tcx.type_of(def_id);
- let trait_ref = tcx.impl_trait_ref(def_id);
- cgp::setup_constraining_predicates(
- tcx,
- &mut predicates,
- trait_ref,
- &mut cgp::parameters_for_impl(self_ty, trait_ref),
- );
- }
-
- ty::GenericPredicates {
- parent: generics.parent,
- predicates: tcx.arena.alloc_from_iter(predicates),
- }
-}
-
-fn const_evaluatable_predicates_of<'tcx>(
- tcx: TyCtxt<'tcx>,
- def_id: LocalDefId,
-) -> FxIndexSet<(ty::Predicate<'tcx>, Span)> {
- struct ConstCollector<'tcx> {
- tcx: TyCtxt<'tcx>,
- preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>,
- }
-
- impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
- fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
- let def_id = self.tcx.hir().local_def_id(c.hir_id);
- let ct = ty::Const::from_anon_const(self.tcx, def_id);
- if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
- assert_eq!(uv.promoted, ());
- let span = self.tcx.hir().span(c.hir_id);
- self.preds.insert((
- ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv))
- .to_predicate(self.tcx),
- span,
- ));
- }
- }
-
- fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::AnonConst) {
- // Do not look into const param defaults,
- // these get checked when they are actually instantiated.
- //
- // We do not want the following to error:
- //
- // struct Foo<const N: usize, const M: usize = { N + 1 }>;
- // struct Bar<const N: usize>(Foo<N, 3>);
- }
- }
-
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let node = tcx.hir().get(hir_id);
-
- let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
- if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(ref impl_) = item.kind {
- if let Some(of_trait) = &impl_.of_trait {
- debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
- collector.visit_trait_ref(of_trait);
- }
-
- debug!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id);
- collector.visit_ty(impl_.self_ty);
- }
-
- if let Some(generics) = node.generics() {
- debug!("const_evaluatable_predicates_of({:?}): visit_generics", def_id);
- collector.visit_generics(generics);
- }
-
- if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) {
- debug!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id);
- collector.visit_fn_decl(fn_sig.decl);
- }
- debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds);
-
- collector.preds
-}
-
-fn trait_explicit_predicates_and_bounds(
- tcx: TyCtxt<'_>,
- def_id: LocalDefId,
-) -> ty::GenericPredicates<'_> {
- assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
- gather_explicit_predicates_of(tcx, def_id.to_def_id())
-}
-
-fn explicit_predicates_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::GenericPredicates<'tcx> {
- let def_kind = tcx.def_kind(def_id);
- if let DefKind::Trait = def_kind {
- // Remove bounds on associated types from the predicates, they will be
- // returned by `explicit_item_bounds`.
- let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
- let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
-
- let is_assoc_item_ty = |ty: Ty<'tcx>| {
- // For a predicate from a where clause to become a bound on an
- // associated type:
- // * It must use the identity substs of the item.
- // * Since any generic parameters on the item are not in scope,
- // this means that the item is not a GAT, and its identity
- // substs are the same as the trait's.
- // * It must be an associated type for this trait (*not* a
- // supertrait).
- if let ty::Projection(projection) = ty.kind() {
- projection.substs == trait_identity_substs
- && tcx.associated_item(projection.item_def_id).container_id(tcx) == def_id
- } else {
- false
- }
- };
-
- let predicates: Vec<_> = predicates_and_bounds
- .predicates
- .iter()
- .copied()
- .filter(|(pred, _)| match pred.kind().skip_binder() {
- ty::PredicateKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
- ty::PredicateKind::Projection(proj) => {
- !is_assoc_item_ty(proj.projection_ty.self_ty())
- }
- ty::PredicateKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
- _ => true,
- })
- .collect();
- if predicates.len() == predicates_and_bounds.predicates.len() {
- predicates_and_bounds
- } else {
- ty::GenericPredicates {
- parent: predicates_and_bounds.parent,
- predicates: tcx.arena.alloc_slice(&predicates),
- }
- }
- } else {
- if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- if tcx.hir().opt_const_param_default_param_hir_id(hir_id).is_some() {
- // In `generics_of` we set the generics' parent to be our parent's parent which means that
- // we lose out on the predicates of our actual parent if we dont return those predicates here.
- // (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
- //
- // struct Foo<T, const N: usize = { <T as Trait>::ASSOC }>(T) where T: Trait;
- // ^^^ ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling
- // ^^^ explicit_predicates_of on
- // parent item we dont have set as the
- // parent of generics returned by `generics_of`
- //
- // In the above code we want the anon const to have predicates in its param env for `T: Trait`
- let item_def_id = tcx.hir().get_parent_item(hir_id);
- // In the above code example we would be calling `explicit_predicates_of(Foo)` here
- return tcx.explicit_predicates_of(item_def_id);
- }
- }
- gather_explicit_predicates_of(tcx, def_id)
- }
-}
-
-/// 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(astconv.tcx(), param_ty).collect()
-}
-
fn compute_sig_of_foreign_fn_decl<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
@@ -2543,7 +1414,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
abi: abi::Abi,
) -> ty::PolyFnSig<'tcx> {
let unsafety = if abi == abi::Abi::RustIntrinsic {
- intrinsic_operation_unsafety(tcx.item_name(def_id))
+ intrinsic_operation_unsafety(tcx, def_id)
} else {
hir::Unsafety::Unsafe
};
@@ -2741,13 +1612,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
}
- // The panic_no_unwind function called by TerminatorKind::Abort will never
- // unwind. If the panic handler that it invokes unwind then it will simply
- // call the panic handler again.
- if Some(did.to_def_id()) == tcx.lang_items().panic_no_unwind() {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
- }
-
let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
let mut inline_span = None;
@@ -2808,7 +1672,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
)
.emit();
}
- } else if attr.has_name(sym::rustc_allocator_nounwind) {
+ } else if attr.has_name(sym::rustc_nounwind) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
} else if attr.has_name(sym::rustc_reallocator) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR;
@@ -3154,6 +2018,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
E0535,
"invalid argument"
)
+ .help("valid inline arguments are `always` and `never`")
.emit();
InlineAttr::None
@@ -3227,11 +2092,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
lint::builtin::INLINE_NO_SANITIZE,
hir_id,
no_sanitize_span,
- |lint| {
- lint.build("`no_sanitize` will have no effect after inlining")
- .span_note(inline_span, "inlining requested here")
- .emit();
- },
+ "`no_sanitize` will have no effect after inlining",
+ |lint| lint.span_note(inline_span, "inlining requested here"),
)
}
}
@@ -3386,7 +2248,7 @@ fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span:
let node = tcx.hir().get(hir_id);
if let Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
let parent_id = tcx.hir().get_parent_item(hir_id);
- let parent_item = tcx.hir().expect_item(parent_id);
+ let parent_item = tcx.hir().expect_item(parent_id.def_id);
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
tcx.sess
.struct_span_err(
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
new file mode 100644
index 000000000..c7777a946
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -0,0 +1,481 @@
+use crate::middle::resolve_lifetime as rl;
+use hir::{
+ intravisit::{self, Visitor},
+ GenericParamKind, HirId, Node,
+};
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_session::lint;
+use rustc_span::symbol::{kw, Symbol};
+use rustc_span::Span;
+
+pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
+ use rustc_hir::*;
+
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+
+ let node = tcx.hir().get(hir_id);
+ let parent_def_id = match node {
+ Node::ImplItem(_)
+ | Node::TraitItem(_)
+ | Node::Variant(_)
+ | Node::Ctor(..)
+ | Node::Field(_) => {
+ let parent_id = tcx.hir().get_parent_item(hir_id);
+ Some(parent_id.to_def_id())
+ }
+ // FIXME(#43408) always enable this once `lazy_normalization` is
+ // stable enough and does not need a feature gate anymore.
+ Node::AnonConst(_) => {
+ let parent_def_id = tcx.hir().get_parent_item(hir_id);
+
+ let mut in_param_ty = false;
+ for (_parent, node) in tcx.hir().parent_iter(hir_id) {
+ if let Some(generics) = node.generics() {
+ let mut visitor = AnonConstInParamTyDetector {
+ in_param_ty: false,
+ found_anon_const_in_param_ty: false,
+ ct: hir_id,
+ };
+
+ visitor.visit_generics(generics);
+ in_param_ty = visitor.found_anon_const_in_param_ty;
+ break;
+ }
+ }
+
+ if in_param_ty {
+ // We do not allow generic parameters in anon consts if we are inside
+ // 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_hir_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 = { .. }>;
+ // ^^^ ^ ^^^^^^ def id of this anon const
+ // ^ ^ param_id
+ // ^ parent_def_id
+ //
+ // then we only want to return generics for params to the left of `N`. If we don't do that we
+ // end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, substs: [N#0])`.
+ //
+ // This causes ICEs (#86580) when building the substs for Foo in `fn foo() -> Foo { .. }` as
+ // we substitute the defaults with the partially built substs when we build the substs. Subst'ing
+ // the `N#0` on the unevaluated const indexes into the empty substs we're in the process of building.
+ //
+ // We fix this by having this function return the parent's generics ourselves and truncating the
+ // generics to only include non-forward declared params (with the exception of the `Self` ty)
+ //
+ // For the above code example that means we want `substs: []`
+ // For the following struct def we want `substs: [N#0]` when generics_of is called on
+ // the def id of the `{ N + 1 }` anon const
+ // struct Foo<const N: usize, const M: usize = { N + 1 }>;
+ //
+ // This has some implications for how we get the predicates available to the anon const
+ // see `explicit_predicates_of` for more information on this
+ let generics = tcx.generics_of(parent_def_id.to_def_id());
+ let param_def = tcx.hir().local_def_id(param_id).to_def_id();
+ let param_def_idx = generics.param_def_id_to_index[&param_def];
+ // In the above example this would be .params[..N#0]
+ let params = generics.params[..param_def_idx as usize].to_owned();
+ let param_def_id_to_index =
+ params.iter().map(|param| (param.def_id, param.index)).collect();
+
+ return ty::Generics {
+ // we set the parent of these generics to be our parent's parent so that we
+ // dont end up with substs: [N, M, N] for the const default on a struct like this:
+ // struct Foo<const N: usize, const M: usize = { ... }>;
+ parent: generics.parent,
+ parent_count: generics.parent_count,
+ params,
+ param_def_id_to_index,
+ has_self: generics.has_self,
+ has_late_bound_regions: generics.has_late_bound_regions,
+ };
+ }
+
+ // 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(tcx.hir().get_parent_node(hir_id));
+ match parent_node {
+ // HACK(eddyb) this provides the correct generics for repeat
+ // expressions' count (i.e. `N` in `[x; N]`), and explicit
+ // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
+ // as they shouldn't be able to cause query cycle errors.
+ Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
+ if constant.hir_id() == hir_id =>
+ {
+ Some(parent_def_id.to_def_id())
+ }
+ Node::Variant(Variant { disr_expr: Some(ref 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))
+ }
+ // Exclude `GlobalAsm` here which cannot have generics.
+ Node::Expr(&Expr { kind: ExprKind::InlineAsm(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,
+ }) =>
+ {
+ Some(parent_def_id.to_def_id())
+ }
+ _ => None,
+ }
+ }
+ }
+ Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
+ Some(tcx.typeck_root_def_id(def_id))
+ }
+ Node::Item(item) => match item.kind {
+ ItemKind::OpaqueTy(hir::OpaqueTy {
+ origin:
+ hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+ in_trait,
+ ..
+ }) => {
+ if in_trait {
+ assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn))
+ } else {
+ assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn))
+ }
+ Some(fn_def_id.to_def_id())
+ }
+ 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);
+ // Opaque types are always nested within another item, and
+ // inherit the generics of the item.
+ Some(parent_id.to_def_id())
+ }
+ _ => None,
+ },
+ _ => None,
+ };
+
+ enum Defaults {
+ Allowed,
+ // See #36887
+ FutureCompatDisallowed,
+ Deny,
+ }
+
+ let no_generics = hir::Generics::empty();
+ let ast_generics = node.generics().unwrap_or(&no_generics);
+ let (opt_self, allow_defaults) = match node {
+ Node::Item(item) => {
+ match item.kind {
+ ItemKind::Trait(..) | ItemKind::TraitAlias(..) => {
+ // Add in the self type parameter.
+ //
+ // Something of a hack: use the node id for the trait, also as
+ // the node id for the Self type parameter.
+ let opt_self = Some(ty::GenericParamDef {
+ index: 0,
+ name: kw::SelfUpper,
+ def_id,
+ pure_wrt_drop: false,
+ kind: ty::GenericParamDefKind::Type {
+ has_default: false,
+ synthetic: false,
+ },
+ });
+
+ (opt_self, Defaults::Allowed)
+ }
+ ItemKind::TyAlias(..)
+ | ItemKind::Enum(..)
+ | ItemKind::Struct(..)
+ | ItemKind::OpaqueTy(..)
+ | ItemKind::Union(..) => (None, Defaults::Allowed),
+ _ => (None, Defaults::FutureCompatDisallowed),
+ }
+ }
+
+ // GATs
+ Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => {
+ (None, Defaults::Deny)
+ }
+ Node::ImplItem(item) if matches!(item.kind, ImplItemKind::Type(..)) => {
+ (None, Defaults::Deny)
+ }
+
+ _ => (None, Defaults::FutureCompatDisallowed),
+ };
+
+ let has_self = opt_self.is_some();
+ let mut parent_has_self = false;
+ let mut own_start = has_self as u32;
+ let parent_count = parent_def_id.map_or(0, |def_id| {
+ let generics = tcx.generics_of(def_id);
+ assert!(!has_self);
+ parent_has_self = generics.has_self;
+ own_start = generics.count() as u32;
+ generics.parent_count + generics.params.len()
+ });
+
+ let mut params: Vec<_> = Vec::with_capacity(ast_generics.params.len() + has_self as usize);
+
+ if let Some(opt_self) = opt_self {
+ params.push(opt_self);
+ }
+
+ let early_lifetimes = super::early_bound_lifetimes_from_generics(tcx, ast_generics);
+ params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
+ name: param.name.ident().name,
+ index: own_start + i as u32,
+ def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
+ pure_wrt_drop: param.pure_wrt_drop,
+ kind: ty::GenericParamDefKind::Lifetime,
+ }));
+
+ // Now create the real type and const parameters.
+ let type_start = own_start - has_self as u32 + params.len() as u32;
+ let mut i = 0;
+ let mut next_index = || {
+ let prev = i;
+ i += 1;
+ prev as u32 + type_start
+ };
+
+ const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
+ `struct`, `enum`, `type`, or `trait` definitions";
+
+ params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
+ GenericParamKind::Lifetime { .. } => None,
+ GenericParamKind::Type { ref default, synthetic, .. } => {
+ if default.is_some() {
+ match allow_defaults {
+ Defaults::Allowed => {}
+ Defaults::FutureCompatDisallowed
+ if tcx.features().default_type_parameter_fallback => {}
+ Defaults::FutureCompatDisallowed => {
+ tcx.struct_span_lint_hir(
+ lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
+ param.hir_id,
+ param.span,
+ TYPE_DEFAULT_NOT_ALLOWED,
+ |lint| lint,
+ );
+ }
+ Defaults::Deny => {
+ tcx.sess.span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED);
+ }
+ }
+ }
+
+ let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic };
+
+ Some(ty::GenericParamDef {
+ index: next_index(),
+ name: param.name.ident().name,
+ def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
+ pure_wrt_drop: param.pure_wrt_drop,
+ kind,
+ })
+ }
+ GenericParamKind::Const { default, .. } => {
+ if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() {
+ tcx.sess.span_err(
+ param.span,
+ "defaults for const parameters are only allowed in \
+ `struct`, `enum`, `type`, or `trait` definitions",
+ );
+ }
+
+ Some(ty::GenericParamDef {
+ index: next_index(),
+ name: param.name.ident().name,
+ def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
+ pure_wrt_drop: param.pure_wrt_drop,
+ kind: ty::GenericParamDefKind::Const { has_default: default.is_some() },
+ })
+ }
+ }));
+
+ // provide junk type parameter defs - the only place that
+ // cares about anything but the length is instantiation,
+ // and we don't do that for closures.
+ if let Node::Expr(&hir::Expr {
+ kind: hir::ExprKind::Closure(hir::Closure { movability: gen, .. }),
+ ..
+ }) = node
+ {
+ let dummy_args = if gen.is_some() {
+ &["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
+ } else {
+ &["<closure_kind>", "<closure_signature>", "<upvars>"][..]
+ };
+
+ params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef {
+ index: next_index(),
+ name: Symbol::intern(arg),
+ def_id,
+ pure_wrt_drop: false,
+ kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
+ }));
+ }
+
+ // provide junk type parameter defs for const blocks.
+ if let Node::AnonConst(_) = node {
+ let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+ if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
+ params.push(ty::GenericParamDef {
+ index: next_index(),
+ name: Symbol::intern("<const_ty>"),
+ def_id,
+ pure_wrt_drop: false,
+ kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
+ });
+ }
+ }
+
+ let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
+
+ ty::Generics {
+ parent: parent_def_id,
+ parent_count,
+ params,
+ param_def_id_to_index,
+ has_self: has_self || parent_has_self,
+ has_late_bound_regions: has_late_bound_regions(tcx, node),
+ }
+}
+
+fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<Span> {
+ struct LateBoundRegionsDetector<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ outer_index: ty::DebruijnIndex,
+ has_late_bound_regions: Option<Span>,
+ }
+
+ impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
+ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
+ if self.has_late_bound_regions.is_some() {
+ return;
+ }
+ match ty.kind {
+ hir::TyKind::BareFn(..) => {
+ self.outer_index.shift_in(1);
+ intravisit::walk_ty(self, ty);
+ self.outer_index.shift_out(1);
+ }
+ _ => intravisit::walk_ty(self, ty),
+ }
+ }
+
+ fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) {
+ if self.has_late_bound_regions.is_some() {
+ return;
+ }
+ self.outer_index.shift_in(1);
+ intravisit::walk_poly_trait_ref(self, tr);
+ self.outer_index.shift_out(1);
+ }
+
+ fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
+ if self.has_late_bound_regions.is_some() {
+ return;
+ }
+
+ match self.tcx.named_region(lt.hir_id) {
+ Some(rl::Region::Static | rl::Region::EarlyBound(..)) => {}
+ Some(rl::Region::LateBound(debruijn, _, _)) if debruijn < self.outer_index => {}
+ Some(rl::Region::LateBound(..) | rl::Region::Free(..)) | None => {
+ self.has_late_bound_regions = Some(lt.span);
+ }
+ }
+ }
+ }
+
+ fn has_late_bound_regions<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ generics: &'tcx hir::Generics<'tcx>,
+ decl: &'tcx hir::FnDecl<'tcx>,
+ ) -> Option<Span> {
+ let mut visitor = LateBoundRegionsDetector {
+ tcx,
+ outer_index: ty::INNERMOST,
+ has_late_bound_regions: None,
+ };
+ for param in generics.params {
+ if let GenericParamKind::Lifetime { .. } = param.kind {
+ if tcx.is_late_bound(param.hir_id) {
+ return Some(param.span);
+ }
+ }
+ }
+ visitor.visit_fn_decl(decl);
+ visitor.has_late_bound_regions
+ }
+
+ match node {
+ Node::TraitItem(item) => match item.kind {
+ hir::TraitItemKind::Fn(ref sig, _) => {
+ has_late_bound_regions(tcx, &item.generics, sig.decl)
+ }
+ _ => None,
+ },
+ Node::ImplItem(item) => match item.kind {
+ hir::ImplItemKind::Fn(ref sig, _) => {
+ has_late_bound_regions(tcx, &item.generics, sig.decl)
+ }
+ _ => None,
+ },
+ Node::ForeignItem(item) => match item.kind {
+ hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
+ has_late_bound_regions(tcx, generics, fn_decl)
+ }
+ _ => None,
+ },
+ Node::Item(item) => match item.kind {
+ hir::ItemKind::Fn(ref sig, .., ref generics, _) => {
+ has_late_bound_regions(tcx, generics, sig.decl)
+ }
+ _ => None,
+ },
+ _ => None,
+ }
+}
+
+struct AnonConstInParamTyDetector {
+ in_param_ty: bool,
+ found_anon_const_in_param_ty: bool,
+ ct: HirId,
+}
+
+impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
+ fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
+ if let GenericParamKind::Const { ty, default: _ } = p.kind {
+ let prev = self.in_param_ty;
+ self.in_param_ty = true;
+ self.visit_ty(ty);
+ self.in_param_ty = prev;
+ }
+ }
+
+ fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
+ if self.in_param_ty && self.ct == c.hir_id {
+ self.found_anon_const_in_param_ty = true;
+ } else {
+ intravisit::walk_anon_const(self, c)
+ }
+ }
+}
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 0d34a8bfe..0d34a8bfe 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
index 4d9704617..3f263a6de 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
@@ -32,8 +32,6 @@ trait RegionExt {
fn id(&self) -> Option<DefId>;
fn shifted(self, amount: u32) -> Region;
-
- fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region;
}
impl RegionExt for Region {
@@ -69,15 +67,6 @@ impl RegionExt for Region {
_ => self,
}
}
-
- fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region {
- match self {
- Region::LateBound(debruijn, index, id) => {
- Region::LateBound(debruijn.shifted_out_to_binder(binder), index, id)
- }
- _ => self,
- }
- }
}
/// Maps the id of each lifetime reference to the lifetime decl
@@ -101,8 +90,8 @@ struct NamedRegionMap {
late_bound_vars: HirIdMap<Vec<ty::BoundVariableKind>>,
}
-pub(crate) struct LifetimeContext<'a, 'tcx> {
- pub(crate) tcx: TyCtxt<'tcx>,
+struct LifetimeContext<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
map: &'a mut NamedRegionMap,
scope: ScopeRef<'a>,
@@ -234,7 +223,7 @@ type ScopeRef<'a> = &'a Scope<'a>;
const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root;
-pub fn provide(providers: &mut ty::query::Providers) {
+pub(crate) fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers {
resolve_lifetimes_trait_definition,
resolve_lifetimes,
@@ -326,6 +315,7 @@ fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetime
}
debug!(?rl.defs);
+ debug!(?rl.late_bound_vars);
rl
}
@@ -339,24 +329,25 @@ fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetime
/// This allows us to avoid cycles. Importantly, if we ask for lifetimes for lifetimes that have an owner
/// other than the trait itself (like the trait methods or associated types), then we just use the regular
/// `resolve_lifetimes`.
-fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx ResolveLifetimes {
- let item_id = item_for(tcx, def_id);
- if item_id == def_id {
- let item = tcx.hir().item(hir::ItemId { def_id: item_id });
+fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: hir::OwnerId) -> &'tcx ResolveLifetimes {
+ let item_id = item_for(tcx, def_id.def_id);
+ let local_def_id = item_id.owner_id.def_id;
+ if item_id.owner_id == def_id {
+ let item = tcx.hir().item(item_id);
match item.kind {
- hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_trait_definition(item_id),
- _ => tcx.resolve_lifetimes(item_id),
+ hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_trait_definition(local_def_id),
+ _ => tcx.resolve_lifetimes(local_def_id),
}
} else {
- tcx.resolve_lifetimes(item_id)
+ tcx.resolve_lifetimes(local_def_id)
}
}
/// Finds the `Item` that contains the given `LocalDefId`
-fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId {
+fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> hir::ItemId {
match tcx.hir().find_by_def_id(local_def_id) {
Some(Node::Item(item)) => {
- return item.def_id;
+ return item.item_id();
}
_ => {}
}
@@ -366,7 +357,7 @@ fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId {
loop {
let node = parent_iter.next().map(|n| n.1);
match node {
- Some(hir::Node::Item(item)) => break item.def_id,
+ Some(hir::Node::Item(item)) => break item.item_id(),
Some(hir::Node::Crate(_)) | None => bug!("Called `item_for` on an Item."),
_ => {}
}
@@ -506,7 +497,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
})
.unzip();
- self.map.late_bound_vars.insert(e.hir_id, binders);
+ self.record_late_bound_vars(e.hir_id, binders);
let scope = Scope::Binder {
hir_id: e.hir_id,
lifetimes,
@@ -530,7 +521,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
match &item.kind {
hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => {
if let Some(of_trait) = of_trait {
- self.map.late_bound_vars.insert(of_trait.hir_ref_id, Vec::default());
+ self.record_late_bound_vars(of_trait.hir_ref_id, Vec::default());
}
}
_ => {}
@@ -566,13 +557,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// their owner, we can keep going until we find the Item that owns that. We then
// conservatively add all resolved lifetimes. Otherwise we run into problems in
// cases like `type Foo<'a> = impl Bar<As = impl Baz + 'a>`.
- for (_hir_id, node) in
- self.tcx.hir().parent_iter(self.tcx.hir().local_def_id_to_hir_id(item.def_id))
- {
+ for (_hir_id, node) in self.tcx.hir().parent_iter(item.owner_id.into()) {
match node {
hir::Node::Item(parent_item) => {
- let resolved_lifetimes: &ResolveLifetimes =
- self.tcx.resolve_lifetimes(item_for(self.tcx, parent_item.def_id));
+ let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes(
+ item_for(self.tcx, parent_item.owner_id.def_id).owner_id.def_id,
+ );
// We need to add *all* deps, since opaque tys may want them from *us*
for (&owner, defs) in resolved_lifetimes.defs.iter() {
defs.iter().for_each(|(&local_id, region)| {
@@ -583,7 +573,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
resolved_lifetimes.late_bound_vars.iter()
{
late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| {
- self.map.late_bound_vars.insert(
+ self.record_late_bound_vars(
hir::HirId { owner, local_id },
late_bound_vars.clone(),
);
@@ -614,7 +604,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
})
.collect();
- self.map.late_bound_vars.insert(item.hir_id(), vec![]);
+ self.record_late_bound_vars(item.hir_id(), vec![]);
let scope = Scope::Binder {
hir_id: item.hir_id(),
lifetimes,
@@ -663,7 +653,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
(pair, r)
})
.unzip();
- self.map.late_bound_vars.insert(ty.hir_id, binders);
+ self.record_late_bound_vars(ty.hir_id, binders);
let scope = Scope::Binder {
hir_id: ty.hir_id,
lifetimes,
@@ -817,7 +807,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {}
}
}
- self.map.late_bound_vars.insert(ty.hir_id, vec![]);
+ self.record_late_bound_vars(ty.hir_id, vec![]);
let scope = Scope::Binder {
hir_id: ty.hir_id,
@@ -861,7 +851,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
})
.collect();
- self.map.late_bound_vars.insert(trait_item.hir_id(), vec![]);
+ self.record_late_bound_vars(trait_item.hir_id(), vec![]);
let scope = Scope::Binder {
hir_id: trait_item.hir_id(),
lifetimes,
@@ -897,7 +887,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
Fn(..) => self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| {
intravisit::walk_impl_item(this, impl_item)
}),
- TyAlias(ref ty) => {
+ Type(ref ty) => {
let generics = &impl_item.generics;
let lifetimes: FxIndexMap<LocalDefId, Region> = generics
.params
@@ -909,9 +899,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => None,
})
.collect();
- self.map.late_bound_vars.insert(ty.hir_id, vec![]);
+ self.record_late_bound_vars(impl_item.hir_id(), vec![]);
let scope = Scope::Binder {
- hir_id: ty.hir_id,
+ hir_id: impl_item.hir_id(),
lifetimes,
s: self.scope,
scope_type: BinderScopeType::Normal,
@@ -995,13 +985,14 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
for predicate in generics.predicates {
match predicate {
&hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+ hir_id,
ref bounded_ty,
bounds,
ref bound_generic_params,
origin,
..
}) => {
- let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
+ let lifetimes: FxIndexMap<LocalDefId, Region> =
bound_generic_params
.iter()
.filter(|param| {
@@ -1009,19 +1000,23 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
})
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair =
- Region::late(late_bound_idx as u32, this.tcx.hir(), param);
- let r = late_region_as_bound_region(this.tcx, &pair.1);
- (pair, r)
+ Region::late(late_bound_idx as u32, this.tcx.hir(), param)
+ })
+ .collect();
+ let binders: Vec<_> =
+ lifetimes
+ .iter()
+ .map(|(_, region)| {
+ late_region_as_bound_region(this.tcx, region)
})
- .unzip();
- this.map.late_bound_vars.insert(bounded_ty.hir_id, binders.clone());
+ .collect();
+ this.record_late_bound_vars(hir_id, binders.clone());
// Even if there are no lifetimes defined here, we still wrap it in a binder
// scope. If there happens to be a nested poly trait ref (an error), that
// will be `Concatenating` anyways, so we don't have to worry about the depth
// being wrong.
let scope = Scope::Binder {
- hir_id: bounded_ty.hir_id,
+ hir_id,
lifetimes,
s: this.scope,
scope_type: BinderScopeType::Normal,
@@ -1089,7 +1084,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// imagine there's a better way to go about this.
let (binders, scope_type) = self.poly_trait_ref_binder_info();
- self.map.late_bound_vars.insert(*hir_id, binders);
+ self.record_late_bound_vars(*hir_id, binders);
let scope = Scope::Binder {
hir_id: *hir_id,
lifetimes: FxIndexMap::default(),
@@ -1127,7 +1122,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
binders.extend(binders_iter);
debug!(?binders);
- self.map.late_bound_vars.insert(trait_ref.trait_ref.hir_ref_id, binders);
+ self.record_late_bound_vars(trait_ref.trait_ref.hir_ref_id, binders);
// Always introduce a scope here, even if this is in a where clause and
// we introduced the binders around the bounded Ty. In that case, we
@@ -1211,6 +1206,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
}
+ fn record_late_bound_vars(&mut self, hir_id: hir::HirId, binder: Vec<ty::BoundVariableKind>) {
+ if let Some(old) = self.map.late_bound_vars.insert(hir_id, binder) {
+ bug!(
+ "overwrote bound vars for {hir_id:?}:\nold={old:?}\nnew={:?}",
+ self.map.late_bound_vars[&hir_id]
+ )
+ }
+ }
+
/// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
///
/// Handles visiting fns and methods. These are a bit complicated because we must distinguish
@@ -1268,7 +1272,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
late_region_as_bound_region(self.tcx, &pair.1)
})
.collect();
- self.map.late_bound_vars.insert(hir_id, binders);
+ self.record_late_bound_vars(hir_id, binders);
let scope = Scope::Binder {
hir_id,
lifetimes,
@@ -1315,15 +1319,44 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
// regular fns.
if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
&& let hir::LifetimeName::Param(_, hir::ParamName::Fresh) = lifetime_ref.name
- && let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner)
+ && let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id)
&& !self.tcx.features().anonymous_lifetime_in_impl_trait
{
- rustc_session::parse::feature_err(
+ let mut diag = rustc_session::parse::feature_err(
&self.tcx.sess.parse_sess,
sym::anonymous_lifetime_in_impl_trait,
lifetime_ref.span,
"anonymous lifetimes in `impl Trait` are unstable",
- ).emit();
+ );
+
+ match self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id) {
+ Some(generics) => {
+
+ let new_param_sugg_tuple;
+
+ new_param_sugg_tuple = match generics.span_for_param_suggestion() {
+ Some(_) => {
+ Some((self.tcx.sess.source_map().span_through_char(generics.span, '<').shrink_to_hi(), "'a, ".to_owned()))
+ },
+ None => Some((generics.span, "<'a>".to_owned()))
+ };
+
+ let mut multi_sugg_vec = vec![(lifetime_ref.span.shrink_to_hi(), "'a ".to_owned())];
+
+ if let Some(new_tuple) = new_param_sugg_tuple{
+ multi_sugg_vec.push(new_tuple);
+ }
+
+ diag.span_label(lifetime_ref.span, "expected named lifetime parameter");
+ diag.multipart_suggestion("consider introducing a named lifetime parameter",
+ multi_sugg_vec,
+ rustc_errors::Applicability::MaybeIncorrect);
+
+ },
+ None => { }
+ }
+
+ diag.emit();
return;
}
scope = s;
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
new file mode 100644
index 000000000..2e84e1d01
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -0,0 +1,707 @@
+use crate::astconv::AstConv;
+use crate::bounds::Bounds;
+use crate::collect::ItemCtxt;
+use crate::constrained_generic_params as cgp;
+use hir::{HirId, Node};
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_middle::ty::subst::InternalSubsts;
+use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+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.
+pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
+ let mut result = tcx.predicates_defined_on(def_id);
+
+ if tcx.is_trait(def_id) {
+ // For traits, add `Self: Trait` predicate. This is
+ // not part of the predicates that a user writes, but it
+ // is something that one must prove in order to invoke a
+ // method or project an associated type.
+ //
+ // In the chalk setup, this predicate is not part of the
+ // "predicates" for a trait item. But it is useful in
+ // rustc because if you directly (e.g.) invoke a trait
+ // method like `Trait::method(...)`, you must naturally
+ // prove that the trait applies to the types that were
+ // used, and adding the predicate into this list ensures
+ // that this is done.
+ //
+ // We use a DUMMY_SP here as a way to signal trait bounds that come
+ // from the trait itself that *shouldn't* be shown as the source of
+ // an obligation and instead be skipped. Otherwise we'd use
+ // `tcx.def_span(def_id);`
+
+ let constness = if tcx.has_attr(def_id, sym::const_trait) {
+ ty::BoundConstness::ConstIfConst
+ } else {
+ ty::BoundConstness::NotConst
+ };
+
+ let span = rustc_span::DUMMY_SP;
+ result.predicates =
+ tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
+ ty::TraitRef::identity(tcx, def_id).with_constness(constness).to_predicate(tcx),
+ span,
+ ))));
+ }
+ debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
+ result
+}
+
+/// Returns a list of user-specified type predicates for the definition with ID `def_id`.
+/// N.B., this does not include any implied/inferred constraints.
+#[instrument(level = "trace", skip(tcx), ret)]
+fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
+ use rustc_hir::*;
+
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+ let node = tcx.hir().get(hir_id);
+
+ let mut is_trait = None;
+ let mut is_default_impl_trait = None;
+
+ let icx = ItemCtxt::new(tcx, def_id);
+
+ const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
+
+ // We use an `IndexSet` to preserves order of insertion.
+ // Preserving the order of insertion is important here so as not to break UI tests.
+ let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
+
+ let ast_generics = match node {
+ Node::TraitItem(item) => item.generics,
+
+ Node::ImplItem(item) => item.generics,
+
+ Node::Item(item) => {
+ match item.kind {
+ ItemKind::Impl(ref impl_) => {
+ if impl_.defaultness.is_default() {
+ is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
+ }
+ &impl_.generics
+ }
+ ItemKind::Fn(.., ref generics, _)
+ | ItemKind::TyAlias(_, ref generics)
+ | ItemKind::Enum(_, ref generics)
+ | ItemKind::Struct(_, ref generics)
+ | ItemKind::Union(_, ref generics) => *generics,
+
+ ItemKind::Trait(_, _, ref generics, ..) => {
+ is_trait = Some(ty::TraitRef::identity(tcx, def_id));
+ *generics
+ }
+ ItemKind::TraitAlias(ref generics, _) => {
+ is_trait = Some(ty::TraitRef::identity(tcx, def_id));
+ *generics
+ }
+ ItemKind::OpaqueTy(OpaqueTy {
+ origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
+ ..
+ }) => {
+ // return-position impl trait
+ //
+ // We don't inherit predicates from the parent here:
+ // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
+ // then the return type is `f::<'static, T>::{{opaque}}`.
+ //
+ // If we inherited the predicates of `f` then we would
+ // require that `T: 'static` to show that the return
+ // type is well-formed.
+ //
+ // The only way to have something with this opaque type
+ // is from the return type of the containing function,
+ // which will ensure that the function's predicates
+ // hold.
+ return ty::GenericPredicates { parent: None, predicates: &[] };
+ }
+ ItemKind::OpaqueTy(OpaqueTy {
+ ref generics,
+ origin: hir::OpaqueTyOrigin::TyAlias,
+ ..
+ }) => {
+ // type-alias impl trait
+ generics
+ }
+
+ _ => NO_GENERICS,
+ }
+ }
+
+ Node::ForeignItem(item) => match item.kind {
+ ForeignItemKind::Static(..) => NO_GENERICS,
+ ForeignItemKind::Fn(_, _, ref generics) => *generics,
+ ForeignItemKind::Type => NO_GENERICS,
+ },
+
+ _ => NO_GENERICS,
+ };
+
+ let generics = tcx.generics_of(def_id);
+ let parent_count = generics.parent_count as u32;
+ let has_own_self = generics.has_self && parent_count == 0;
+
+ // 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.super_predicates_of(def_id).predicates.iter().cloned());
+ }
+
+ // In default impls, we can assume that the self type implements
+ // the trait. So in:
+ //
+ // default impl Foo for Bar { .. }
+ //
+ // we add a default where clause `Foo: Bar`. We do a similar thing for traits
+ // (see below). Recall that a default impl is not itself an impl, but rather a
+ // set of defaults that can be incorporated into another impl.
+ if let Some(trait_ref) = is_default_impl_trait {
+ predicates.insert((trait_ref.without_const().to_predicate(tcx), tcx.def_span(def_id)));
+ }
+
+ // Collect the region predicates that were declared inline as
+ // well. In the case of parameters declared on a fn or method, we
+ // have to be careful to only iterate over early-bound regions.
+ let mut index = parent_count
+ + has_own_self as u32
+ + super::early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32;
+
+ trace!(?predicates);
+ trace!(?ast_generics);
+
+ // Collect the predicates that were written inline by the user on each
+ // type parameter (e.g., `<T: Foo>`).
+ for param in ast_generics.params {
+ match param.kind {
+ // We already dealt with early bound lifetimes above.
+ GenericParamKind::Lifetime { .. } => (),
+ GenericParamKind::Type { .. } => {
+ let name = param.name.ident().name;
+ let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
+ index += 1;
+
+ let mut bounds = Bounds::default();
+ // Params are implicitly sized unless a `?Sized` bound is found
+ <dyn AstConv<'_>>::add_implicitly_sized(
+ &icx,
+ &mut bounds,
+ &[],
+ Some((param.hir_id, ast_generics.predicates)),
+ param.span,
+ );
+ trace!(?bounds);
+ predicates.extend(bounds.predicates(tcx, param_ty));
+ trace!(?predicates);
+ }
+ GenericParamKind::Const { .. } => {
+ // Bounds on const parameters are currently not possible.
+ index += 1;
+ }
+ }
+ }
+
+ trace!(?predicates);
+ // Add in the bounds that appear in the where-clause.
+ for predicate in ast_generics.predicates {
+ match predicate {
+ hir::WherePredicate::BoundPredicate(bound_pred) => {
+ let ty = icx.to_ty(bound_pred.bounded_ty);
+ let bound_vars = icx.tcx.late_bound_vars(bound_pred.hir_id);
+
+ // Keep the type around in a dummy predicate, in case of no bounds.
+ // That way, `where Ty:` is not a complete noop (see #53696) and `Ty`
+ // is still checked for WF.
+ if bound_pred.bounds.is_empty() {
+ if let ty::Param(_) = ty.kind() {
+ // This is a `where T:`, which can be in the HIR from the
+ // transformation that moves `?Sized` to `T`'s declaration.
+ // We can skip the predicate because type parameters are
+ // trivially WF, but also we *should*, to avoid exposing
+ // users who never wrote `where Type:,` themselves, to
+ // compiler/tooling bugs from not handling WF predicates.
+ } else {
+ let span = bound_pred.bounded_ty.span;
+ let predicate = ty::Binder::bind_with_vars(
+ ty::PredicateKind::WellFormed(ty.into()),
+ bound_vars,
+ );
+ predicates.insert((predicate.to_predicate(tcx), span));
+ }
+ }
+
+ let mut bounds = Bounds::default();
+ <dyn AstConv<'_>>::add_bounds(
+ &icx,
+ ty,
+ bound_pred.bounds.iter(),
+ &mut bounds,
+ bound_vars,
+ );
+ predicates.extend(bounds.predicates(tcx, ty));
+ }
+
+ hir::WherePredicate::RegionPredicate(region_pred) => {
+ let r1 = <dyn AstConv<'_>>::ast_region_to_region(&icx, &region_pred.lifetime, None);
+ predicates.extend(region_pred.bounds.iter().map(|bound| {
+ let (r2, span) = match bound {
+ hir::GenericBound::Outlives(lt) => {
+ (<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.span)
+ }
+ _ => bug!(),
+ };
+ let pred = ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
+ ty::OutlivesPredicate(r1, r2),
+ ))
+ .to_predicate(icx.tcx);
+
+ (pred, span)
+ }))
+ }
+
+ hir::WherePredicate::EqPredicate(..) => {
+ // FIXME(#20041)
+ }
+ }
+ }
+
+ if tcx.features().generic_const_exprs {
+ predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
+ }
+
+ let mut predicates: Vec<_> = predicates.into_iter().collect();
+
+ // Subtle: before we store the predicates into the tcx, we
+ // sort them so that predicates like `T: Foo<Item=U>` come
+ // before uses of `U`. This avoids false ambiguity errors
+ // in trait checking. See `setup_constraining_predicates`
+ // for details.
+ if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
+ let self_ty = tcx.type_of(def_id);
+ let trait_ref = tcx.impl_trait_ref(def_id);
+ cgp::setup_constraining_predicates(
+ tcx,
+ &mut predicates,
+ trait_ref,
+ &mut cgp::parameters_for_impl(self_ty, trait_ref),
+ );
+ }
+
+ ty::GenericPredicates {
+ parent: generics.parent,
+ predicates: tcx.arena.alloc_from_iter(predicates),
+ }
+}
+
+fn const_evaluatable_predicates_of<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: LocalDefId,
+) -> FxIndexSet<(ty::Predicate<'tcx>, Span)> {
+ struct ConstCollector<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>,
+ }
+
+ impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
+ fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
+ let def_id = self.tcx.hir().local_def_id(c.hir_id);
+ let ct = ty::Const::from_anon_const(self.tcx, def_id);
+ if let ty::ConstKind::Unevaluated(_) = ct.kind() {
+ let span = self.tcx.hir().span(c.hir_id);
+ self.preds.insert((
+ ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct))
+ .to_predicate(self.tcx),
+ span,
+ ));
+ }
+ }
+
+ fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::AnonConst) {
+ // Do not look into const param defaults,
+ // these get checked when they are actually instantiated.
+ //
+ // We do not want the following to error:
+ //
+ // struct Foo<const N: usize, const M: usize = { N + 1 }>;
+ // struct Bar<const N: usize>(Foo<N, 3>);
+ }
+ }
+
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let node = tcx.hir().get(hir_id);
+
+ let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
+ if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(ref impl_) = item.kind {
+ if let Some(of_trait) = &impl_.of_trait {
+ debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
+ collector.visit_trait_ref(of_trait);
+ }
+
+ debug!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id);
+ collector.visit_ty(impl_.self_ty);
+ }
+
+ if let Some(generics) = node.generics() {
+ debug!("const_evaluatable_predicates_of({:?}): visit_generics", def_id);
+ collector.visit_generics(generics);
+ }
+
+ if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) {
+ debug!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id);
+ collector.visit_fn_decl(fn_sig.decl);
+ }
+ debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds);
+
+ collector.preds
+}
+
+pub(super) fn trait_explicit_predicates_and_bounds(
+ tcx: TyCtxt<'_>,
+ def_id: LocalDefId,
+) -> ty::GenericPredicates<'_> {
+ assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
+ gather_explicit_predicates_of(tcx, def_id.to_def_id())
+}
+
+pub(super) fn explicit_predicates_of<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+) -> ty::GenericPredicates<'tcx> {
+ let def_kind = tcx.def_kind(def_id);
+ if let DefKind::Trait = def_kind {
+ // Remove bounds on associated types from the predicates, they will be
+ // returned by `explicit_item_bounds`.
+ let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
+ let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
+
+ let is_assoc_item_ty = |ty: Ty<'tcx>| {
+ // For a predicate from a where clause to become a bound on an
+ // associated type:
+ // * It must use the identity substs of the item.
+ // * Since any generic parameters on the item are not in scope,
+ // this means that the item is not a GAT, and its identity
+ // substs are the same as the trait's.
+ // * It must be an associated type for this trait (*not* a
+ // supertrait).
+ if let ty::Projection(projection) = ty.kind() {
+ projection.substs == trait_identity_substs
+ && tcx.associated_item(projection.item_def_id).container_id(tcx) == def_id
+ } else {
+ false
+ }
+ };
+
+ let predicates: Vec<_> = predicates_and_bounds
+ .predicates
+ .iter()
+ .copied()
+ .filter(|(pred, _)| match pred.kind().skip_binder() {
+ ty::PredicateKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
+ ty::PredicateKind::Projection(proj) => {
+ !is_assoc_item_ty(proj.projection_ty.self_ty())
+ }
+ ty::PredicateKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
+ _ => true,
+ })
+ .collect();
+ if predicates.len() == predicates_and_bounds.predicates.len() {
+ predicates_and_bounds
+ } else {
+ ty::GenericPredicates {
+ parent: predicates_and_bounds.parent,
+ predicates: tcx.arena.alloc_slice(&predicates),
+ }
+ }
+ } else {
+ if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+ if tcx.hir().opt_const_param_default_param_hir_id(hir_id).is_some() {
+ // In `generics_of` we set the generics' parent to be our parent's parent which means that
+ // we lose out on the predicates of our actual parent if we dont return those predicates here.
+ // (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
+ //
+ // struct Foo<T, const N: usize = { <T as Trait>::ASSOC }>(T) where T: Trait;
+ // ^^^ ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling
+ // ^^^ explicit_predicates_of on
+ // parent item we dont have set as the
+ // parent of generics returned by `generics_of`
+ //
+ // In the above code we want the anon const to have predicates in its param env for `T: Trait`
+ let item_def_id = tcx.hir().get_parent_item(hir_id);
+ // In the above code example we would be calling `explicit_predicates_of(Foo)` here
+ return tcx.explicit_predicates_of(item_def_id);
+ }
+ }
+ gather_explicit_predicates_of(tcx, def_id)
+ }
+}
+
+/// Ensures that the super-predicates of the trait with a `DefId`
+/// of `trait_def_id` are converted and stored. This also ensures that
+/// the transitive super-predicates are converted.
+pub(super) fn super_predicates_of(
+ tcx: TyCtxt<'_>,
+ trait_def_id: DefId,
+) -> ty::GenericPredicates<'_> {
+ tcx.super_predicates_that_define_assoc_type((trait_def_id, None))
+}
+
+/// Ensures that the super-predicates of the trait with a `DefId`
+/// of `trait_def_id` are converted and stored. This also ensures that
+/// the transitive super-predicates are converted.
+pub(super) fn super_predicates_that_define_assoc_type(
+ tcx: TyCtxt<'_>,
+ (trait_def_id, assoc_name): (DefId, Option<Ident>),
+) -> ty::GenericPredicates<'_> {
+ if trait_def_id.is_local() {
+ debug!("local trait");
+ let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local());
+
+ let Node::Item(item) = tcx.hir().get(trait_hir_id) else {
+ bug!("trait_node_id {} is not an item", trait_hir_id);
+ };
+
+ let (generics, bounds) = match item.kind {
+ hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits),
+ hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits),
+ _ => span_bug!(item.span, "super_predicates invoked on non-trait"),
+ };
+
+ let icx = ItemCtxt::new(tcx, trait_def_id);
+
+ // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
+ let self_param_ty = tcx.types.self_param;
+ let superbounds1 = if let Some(assoc_name) = assoc_name {
+ <dyn AstConv<'_>>::compute_bounds_that_match_assoc_type(
+ &icx,
+ self_param_ty,
+ bounds,
+ assoc_name,
+ )
+ } else {
+ <dyn AstConv<'_>>::compute_bounds(&icx, self_param_ty, bounds)
+ };
+
+ let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
+
+ // Convert any explicit superbounds in the where-clause,
+ // e.g., `trait Foo where Self: Bar`.
+ // In the case of trait aliases, however, we include all bounds in the where-clause,
+ // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
+ // as one of its "superpredicates".
+ let is_trait_alias = tcx.is_trait_alias(trait_def_id);
+ let superbounds2 = icx.type_parameter_bounds_in_generics(
+ generics,
+ item.hir_id(),
+ self_param_ty,
+ OnlySelfBounds(!is_trait_alias),
+ assoc_name,
+ );
+
+ // Combine the two lists to form the complete set of superbounds:
+ let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
+ debug!(?superbounds);
+
+ // Now require that immediate supertraits are converted,
+ // which will, in turn, reach indirect supertraits.
+ if assoc_name.is_none() {
+ // Now require that immediate supertraits are converted,
+ // which will, in turn, reach indirect supertraits.
+ for &(pred, span) in superbounds {
+ debug!("superbound: {:?}", pred);
+ if let ty::PredicateKind::Trait(bound) = pred.kind().skip_binder() {
+ tcx.at(span).super_predicates_of(bound.def_id());
+ }
+ }
+ }
+
+ ty::GenericPredicates { parent: None, predicates: superbounds }
+ } else {
+ // if `assoc_name` is None, then the query should've been redirected to an
+ // external provider
+ assert!(assoc_name.is_some());
+ tcx.super_predicates_of(trait_def_id)
+ }
+}
+
+/// Returns the predicates defined on `item_def_id` of the form
+/// `X: Foo` where `X` is the type parameter `def_id`.
+#[instrument(level = "trace", skip(tcx))]
+pub(super) fn type_param_predicates(
+ tcx: TyCtxt<'_>,
+ (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident),
+) -> ty::GenericPredicates<'_> {
+ use rustc_hir::*;
+
+ // In the AST, bounds can derive from two places. Either
+ // written inline like `<T: Foo>` or in a where-clause like
+ // `where T: Foo`.
+
+ let param_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let param_owner = tcx.hir().ty_param_owner(def_id);
+ let generics = tcx.generics_of(param_owner);
+ let index = generics.param_def_id_to_index[&def_id.to_def_id()];
+ let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id));
+
+ // Don't look for bounds where the type parameter isn't in scope.
+ let parent = if item_def_id == param_owner.to_def_id() {
+ None
+ } else {
+ tcx.generics_of(item_def_id).parent
+ };
+
+ let mut result = parent
+ .map(|parent| {
+ let icx = ItemCtxt::new(tcx, parent);
+ icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name)
+ })
+ .unwrap_or_default();
+ let mut extend = None;
+
+ let item_hir_id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local());
+ let ast_generics = match tcx.hir().get(item_hir_id) {
+ Node::TraitItem(item) => &item.generics,
+
+ Node::ImplItem(item) => &item.generics,
+
+ Node::Item(item) => {
+ match item.kind {
+ ItemKind::Fn(.., ref generics, _)
+ | ItemKind::Impl(hir::Impl { ref generics, .. })
+ | ItemKind::TyAlias(_, ref generics)
+ | ItemKind::OpaqueTy(OpaqueTy {
+ ref generics,
+ origin: hir::OpaqueTyOrigin::TyAlias,
+ ..
+ })
+ | ItemKind::Enum(_, ref generics)
+ | ItemKind::Struct(_, ref generics)
+ | ItemKind::Union(_, ref generics) => generics,
+ ItemKind::Trait(_, _, ref generics, ..) => {
+ // Implied `Self: Trait` and supertrait bounds.
+ if param_id == item_hir_id {
+ let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
+ extend =
+ Some((identity_trait_ref.without_const().to_predicate(tcx), item.span));
+ }
+ generics
+ }
+ _ => return result,
+ }
+ }
+
+ Node::ForeignItem(item) => match item.kind {
+ ForeignItemKind::Fn(_, _, ref generics) => generics,
+ _ => return result,
+ },
+
+ _ => return result,
+ };
+
+ let icx = ItemCtxt::new(tcx, item_def_id);
+ let extra_predicates = extend.into_iter().chain(
+ icx.type_parameter_bounds_in_generics(
+ ast_generics,
+ param_id,
+ ty,
+ OnlySelfBounds(true),
+ Some(assoc_name),
+ )
+ .into_iter()
+ .filter(|(predicate, _)| match predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(data) => data.self_ty().is_param(index),
+ _ => false,
+ }),
+ );
+ result.predicates =
+ tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(extra_predicates));
+ result
+}
+
+impl<'tcx> ItemCtxt<'tcx> {
+ /// Finds bounds from `hir::Generics`. This requires scanning through the
+ /// AST. We do this to avoid having to convert *all* the bounds, which
+ /// would create artificial cycles. Instead, we can only convert the
+ /// bounds for a type parameter `X` if `X::Foo` is used.
+ #[instrument(level = "trace", skip(self, ast_generics))]
+ fn type_parameter_bounds_in_generics(
+ &self,
+ ast_generics: &'tcx hir::Generics<'tcx>,
+ param_id: hir::HirId,
+ ty: Ty<'tcx>,
+ only_self_bounds: OnlySelfBounds,
+ assoc_name: Option<Ident>,
+ ) -> Vec<(ty::Predicate<'tcx>, Span)> {
+ let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
+ trace!(?param_def_id);
+ ast_generics
+ .predicates
+ .iter()
+ .filter_map(|wp| match *wp {
+ hir::WherePredicate::BoundPredicate(ref bp) => Some(bp),
+ _ => None,
+ })
+ .flat_map(|bp| {
+ let bt = if bp.is_param_bound(param_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()
+ }
+
+ #[instrument(level = "trace", skip(self))]
+ fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
+ match b {
+ 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)
+ } else {
+ false
+ }
+ }
+ _ => false,
+ }
+ }
+}
+
+/// 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(astconv.tcx(), param_ty).collect()
+}
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index a1d1f125f..c29a645eb 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -284,7 +284,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
icx.to_ty(ty)
}
}
- ImplItemKind::TyAlias(ty) => {
+ ImplItemKind::Type(ty) => {
if tcx.impl_trait_ref(tcx.hir().get_parent_item(hir_id)).is_none() {
check_feature_inherent_assoc_ty(tcx, item.span);
}
@@ -319,7 +319,15 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
}
}
ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
- ItemKind::Impl(hir::Impl { self_ty, .. }) => icx.to_ty(*self_ty),
+ ItemKind::Impl(hir::Impl { self_ty, .. }) => {
+ match self_ty.find_self_aliases() {
+ spans if spans.len() > 0 => {
+ tcx.sess.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: (), });
+ tcx.ty_error()
+ },
+ _ => icx.to_ty(*self_ty),
+ }
+ },
ItemKind::Fn(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
tcx.mk_fn_def(def_id.to_def_id(), substs)
@@ -340,10 +348,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
..
}) => {
if in_trait {
- span_bug!(item.span, "impl-trait in trait has no default")
- } else {
- find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
+ assert!(tcx.impl_defaultness(owner).has_value());
}
+ find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
}
ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
@@ -493,8 +500,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
},
def_id.to_def_id(),
);
- if let Some(assoc_item) = assoc_item {
- tcx.type_of(tcx.generics_of(assoc_item.def_id).params[idx].def_id)
+ if let Some(param)
+ = assoc_item.map(|item| &tcx.generics_of(item.def_id).params[idx]).filter(|param| param.kind.is_ty_or_const())
+ {
+ tcx.type_of(param.def_id)
} else {
// FIXME(associated_const_equality): add a useful error message here.
tcx.ty_error_with_message(
@@ -564,6 +573,11 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
/// 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 now. 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<'_> {
@@ -590,18 +604,23 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error() });
return;
}
- if !tables.concrete_opaque_types.contains_key(&self.def_id) {
+ 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) = self.found {
- if concrete_type.ty != prev.ty && !(concrete_type, prev).references_error() {
+ if let Some(prev) = &mut self.found {
+ if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
prev.report_mismatch(&concrete_type, self.tcx);
+ prev.ty = self.tcx.ty_error();
}
} else {
self.found = Some(concrete_type);
@@ -624,31 +643,31 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
intravisit::walk_expr(self, ex);
}
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
- trace!(?it.def_id);
+ trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
- if it.def_id != self.def_id {
- self.check(it.def_id);
+ 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.def_id);
+ trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
- if it.def_id != self.def_id {
- self.check(it.def_id);
+ 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.def_id);
- self.check(it.def_id);
+ 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: def_id, tcx, found: None };
+ let mut locator = ConstraintLocator { def_id: def_id, tcx, found: None, typeck_types: vec![] };
debug!(?scope);
@@ -678,16 +697,32 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
}
}
- match locator.found {
- Some(hidden) => hidden.ty,
- None => {
- tcx.sess.emit_err(UnconstrainedOpaqueType {
- span: tcx.def_span(def_id),
- name: tcx.item_name(tcx.local_parent(def_id).to_def_id()),
- });
- tcx.ty_error()
+ let Some(hidden) = locator.found else {
+ 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();
+ };
+
+ // 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(
@@ -743,24 +778,24 @@ fn find_opaque_ty_constraints_for_rpit(
intravisit::walk_expr(self, ex);
}
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
- trace!(?it.def_id);
+ trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
- if it.def_id != self.def_id {
- self.check(it.def_id);
+ 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.def_id);
+ trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
- if it.def_id != self.def_id {
- self.check(it.def_id);
+ 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.def_id);
- self.check(it.def_id);
+ trace!(?it.owner_id);
+ self.check(it.owner_id.def_id);
intravisit::walk_trait_item(self, it);
}
}
@@ -788,20 +823,15 @@ fn find_opaque_ty_constraints_for_rpit(
// the `concrete_opaque_types` table.
tcx.ty_error()
} else {
- table
- .concrete_opaque_types
- .get(&def_id)
- .copied()
- .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.
- Some(tcx.mk_diverging_default())
- })
- .expect("RPIT always have a hidden type from typeck")
+ 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()
+ })
}
})
}
diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index 8428e4664..213b89fc7 100644
--- a/compiler/rustc_typeck/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -114,9 +114,9 @@ pub fn identify_constrained_generic_params<'tcx>(
/// ```
/// The impl's predicates are collected from left to right. Ignoring
/// the implicit `Sized` bounds, these are
-/// * T: Debug
-/// * U: Iterator
-/// * <U as Iterator>::Item = T -- a desugared ProjectionPredicate
+/// * `T: Debug`
+/// * `U: Iterator`
+/// * `<U as Iterator>::Item = T` -- a desugared ProjectionPredicate
///
/// When we, for example, try to go over the trait-reference
/// `IntoIter<u32> as Trait`, we substitute the impl parameters with fresh
@@ -132,12 +132,16 @@ pub fn identify_constrained_generic_params<'tcx>(
///
/// We *do* have to be somewhat careful when projection targets contain
/// projections themselves, for example in
+///
+/// ```ignore (illustrative)
/// impl<S,U,V,W> Trait for U where
/// /* 0 */ S: Iterator<Item = U>,
/// /* - */ U: Iterator,
/// /* 1 */ <U as Iterator>::Item: ToOwned<Owned=(W,<V as Iterator>::Item)>
/// /* 2 */ W: Iterator<Item = V>
/// /* 3 */ V: Debug
+/// ```
+///
/// we have to evaluate the projections in the order I wrote them:
/// `V: Debug` requires `V` to be evaluated. The only projection that
/// *determines* `V` is 2 (1 contains it, but *does not determine it*,
diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 0d2e66745..d5b1a7ce1 100644
--- a/compiler/rustc_typeck/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1,23 +1,13 @@
-//! Errors emitted by typeck.
+//! Errors emitted by `rustc_hir_analysis`.
+
use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler};
-use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
+use rustc_errors::{IntoDiagnostic, MultiSpan};
+use rustc_macros::{Diagnostic, LintDiagnostic};
use rustc_middle::ty::Ty;
-use rustc_session::SessionDiagnostic;
use rustc_span::{symbol::Ident, Span, Symbol};
-#[derive(SessionDiagnostic)]
-#[diag(typeck::field_multiply_specified_in_initializer, code = "E0062")]
-pub struct FieldMultiplySpecifiedInInitializer {
- #[primary_span]
- #[label]
- pub span: Span,
- #[label(typeck::previous_use_label)]
- pub prev_span: Span,
- pub ident: Ident,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(typeck::unrecognized_atomic_operation, code = "E0092")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_unrecognized_atomic_operation, code = "E0092")]
pub struct UnrecognizedAtomicOperation<'a> {
#[primary_span]
#[label]
@@ -25,8 +15,8 @@ pub struct UnrecognizedAtomicOperation<'a> {
pub op: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")]
pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
#[primary_span]
#[label]
@@ -36,8 +26,8 @@ pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
pub descr: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::unrecognized_intrinsic_function, code = "E0093")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_unrecognized_intrinsic_function, code = "E0093")]
pub struct UnrecognizedIntrinsicFunction {
#[primary_span]
#[label]
@@ -45,93 +35,86 @@ pub struct UnrecognizedIntrinsicFunction {
pub name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::lifetimes_or_bounds_mismatch_on_trait, code = "E0195")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_lifetimes_or_bounds_mismatch_on_trait, code = "E0195")]
pub struct LifetimesOrBoundsMismatchOnTrait {
#[primary_span]
#[label]
pub span: Span,
- #[label(typeck::generics_label)]
+ #[label(generics_label)]
pub generics_span: Option<Span>,
pub item_kind: &'static str,
pub ident: Ident,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::drop_impl_on_wrong_item, code = "E0120")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_drop_impl_on_wrong_item, code = "E0120")]
pub struct DropImplOnWrongItem {
#[primary_span]
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::field_already_declared, code = "E0124")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_field_already_declared, code = "E0124")]
pub struct FieldAlreadyDeclared {
pub field_name: Ident,
#[primary_span]
#[label]
pub span: Span,
- #[label(typeck::previous_decl_label)]
+ #[label(previous_decl_label)]
pub prev_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::copy_impl_on_type_with_dtor, code = "E0184")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_copy_impl_on_type_with_dtor, code = "E0184")]
pub struct CopyImplOnTypeWithDtor {
#[primary_span]
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::multiple_relaxed_default_bounds, code = "E0203")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_multiple_relaxed_default_bounds, code = "E0203")]
pub struct MultipleRelaxedDefaultBounds {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::copy_impl_on_non_adt, code = "E0206")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_copy_impl_on_non_adt, code = "E0206")]
pub struct CopyImplOnNonAdt {
#[primary_span]
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::trait_object_declared_with_no_traits, code = "E0224")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_trait_object_declared_with_no_traits, code = "E0224")]
pub struct TraitObjectDeclaredWithNoTraits {
#[primary_span]
pub span: Span,
- #[label(typeck::alias_span)]
+ #[label(alias_span)]
pub trait_alias_span: Option<Span>,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::ambiguous_lifetime_bound, code = "E0227")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_ambiguous_lifetime_bound, code = "E0227")]
pub struct AmbiguousLifetimeBound {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::assoc_type_binding_not_allowed, code = "E0229")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_assoc_type_binding_not_allowed, code = "E0229")]
pub struct AssocTypeBindingNotAllowed {
#[primary_span]
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::functional_record_update_on_non_struct, code = "E0436")]
-pub struct FunctionalRecordUpdateOnNonStruct {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(typeck::typeof_reserved_keyword_used, code = "E0516")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_typeof_reserved_keyword_used, code = "E0516")]
pub struct TypeofReservedKeywordUsed<'tcx> {
pub ty: Ty<'tcx>,
#[primary_span]
@@ -141,104 +124,26 @@ pub struct TypeofReservedKeywordUsed<'tcx> {
pub opt_sugg: Option<(Span, Applicability)>,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::return_stmt_outside_of_fn_body, code = "E0572")]
-pub struct ReturnStmtOutsideOfFnBody {
- #[primary_span]
- pub span: Span,
- #[label(typeck::encl_body_label)]
- pub encl_body_span: Option<Span>,
- #[label(typeck::encl_fn_label)]
- pub encl_fn_span: Option<Span>,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(typeck::yield_expr_outside_of_generator, code = "E0627")]
-pub struct YieldExprOutsideOfGenerator {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(typeck::struct_expr_non_exhaustive, code = "E0639")]
-pub struct StructExprNonExhaustive {
- #[primary_span]
- pub span: Span,
- pub what: &'static str,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(typeck::method_call_on_unknown_type, code = "E0699")]
-pub struct MethodCallOnUnknownType {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(typeck::value_of_associated_struct_already_specified, code = "E0719")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_value_of_associated_struct_already_specified, code = "E0719")]
pub struct ValueOfAssociatedStructAlreadySpecified {
#[primary_span]
#[label]
pub span: Span,
- #[label(typeck::previous_bound_label)]
+ #[label(previous_bound_label)]
pub prev_span: Span,
pub item_name: Ident,
pub def_path: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::address_of_temporary_taken, code = "E0745")]
-pub struct AddressOfTemporaryTaken {
- #[primary_span]
- #[label]
- pub span: Span,
-}
-
-#[derive(SessionSubdiagnostic)]
-pub enum AddReturnTypeSuggestion {
- #[suggestion(
- typeck::add_return_type_add,
- code = "-> {found} ",
- applicability = "machine-applicable"
- )]
- Add {
- #[primary_span]
- span: Span,
- found: String,
- },
- #[suggestion(
- typeck::add_return_type_missing_here,
- code = "-> _ ",
- applicability = "has-placeholders"
- )]
- MissingHere {
- #[primary_span]
- span: Span,
- },
-}
-
-#[derive(SessionSubdiagnostic)]
-pub enum ExpectedReturnTypeLabel<'tcx> {
- #[label(typeck::expected_default_return_type)]
- Unit {
- #[primary_span]
- span: Span,
- },
- #[label(typeck::expected_return_type)]
- Other {
- #[primary_span]
- span: Span,
- expected: Ty<'tcx>,
- },
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(typeck::unconstrained_opaque_type)]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_unconstrained_opaque_type)]
#[note]
pub struct UnconstrainedOpaqueType {
#[primary_span]
pub span: Span,
pub name: Symbol,
+ pub what: &'static str,
}
pub struct MissingTypeParams {
@@ -249,12 +154,12 @@ pub struct MissingTypeParams {
pub empty_generic_args: bool,
}
-// Manual implementation of `SessionDiagnostic` to be able to call `span_to_snippet`.
-impl<'a> SessionDiagnostic<'a> for MissingTypeParams {
+// Manual implementation of `IntoDiagnostic` to be able to call `span_to_snippet`.
+impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut err = handler.struct_span_err_with_code(
self.span,
- rustc_errors::fluent::typeck::missing_type_params,
+ rustc_errors::fluent::hir_analysis_missing_type_params,
error_code!(E0393),
);
err.set_arg("parameterCount", self.missing_type_params.len());
@@ -267,7 +172,7 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams {
.join(", "),
);
- err.span_label(self.def_span, rustc_errors::fluent::typeck::label);
+ err.span_label(self.def_span, rustc_errors::fluent::label);
let mut suggested = false;
// Don't suggest setting the type params if there are some already: the order is
@@ -282,7 +187,7 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams {
// least we can clue them to the correct syntax `Iterator<Type>`.
err.span_suggestion(
self.span,
- rustc_errors::fluent::typeck::suggestion,
+ rustc_errors::fluent::suggestion,
format!(
"{}<{}>",
snippet,
@@ -298,16 +203,16 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams {
}
}
if !suggested {
- err.span_label(self.span, rustc_errors::fluent::typeck::no_suggestion_label);
+ err.span_label(self.span, rustc_errors::fluent::no_suggestion_label);
}
- err.note(rustc_errors::fluent::typeck::note);
+ err.note(rustc_errors::fluent::note);
err
}
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::manual_implementation, code = "E0183")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_manual_implementation, code = "E0183")]
#[help]
pub struct ManualImplementation {
#[primary_span]
@@ -316,22 +221,22 @@ pub struct ManualImplementation {
pub trait_name: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::substs_on_overridden_impl)]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_substs_on_overridden_impl)]
pub struct SubstsOnOverriddenImpl {
#[primary_span]
pub span: Span,
}
#[derive(LintDiagnostic)]
-#[diag(typeck::unused_extern_crate)]
+#[diag(hir_analysis_unused_extern_crate)]
pub struct UnusedExternCrate {
#[suggestion(applicability = "machine-applicable", code = "")]
pub span: Span,
}
#[derive(LintDiagnostic)]
-#[diag(typeck::extern_crate_not_idiomatic)]
+#[diag(hir_analysis_extern_crate_not_idiomatic)]
pub struct ExternCrateNotIdiomatic {
#[suggestion_short(applicability = "machine-applicable", code = "{suggestion_code}")]
pub span: Span,
@@ -339,9 +244,39 @@ pub struct ExternCrateNotIdiomatic {
pub suggestion_code: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::expected_used_symbol)]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_expected_used_symbol)]
pub struct ExpectedUsedSymbol {
#[primary_span]
pub span: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_const_impl_for_non_const_trait)]
+pub struct ConstImplForNonConstTrait {
+ #[primary_span]
+ pub trait_ref_span: Span,
+ pub trait_name: String,
+ #[suggestion(applicability = "machine-applicable", code = "#[const_trait]")]
+ pub local_trait_span: Option<Span>,
+ #[note]
+ pub marking: (),
+ #[note(adding)]
+ pub adding: (),
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_const_bound_for_non_const_trait)]
+pub struct ConstBoundForNonConstTrait {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_self_in_impl_self)]
+pub struct SelfInImplSelf {
+ #[primary_span]
+ pub span: MultiSpan,
+ #[note]
+ pub note: (),
+}
diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 7b080dc29..b0fdfcf38 100644
--- a/compiler/rustc_typeck/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -64,38 +64,36 @@ fn diagnostic_hir_wf_check<'tcx>(
impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
- self.tcx.infer_ctxt().enter(|infcx| {
- let tcx_ty =
- self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
- let cause = traits::ObligationCause::new(
- ty.span,
- self.hir_id,
- traits::ObligationCauseCode::WellFormed(None),
- );
- let errors = traits::fully_solve_obligation(
- &infcx,
- traits::Obligation::new(
- cause,
- self.param_env,
- ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into()))
- .to_predicate(self.tcx),
- ),
- );
- if !errors.is_empty() {
- debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
- for error in errors {
- if error.obligation.predicate == self.predicate {
- // Save the cause from the greatest depth - this corresponds
- // to picking more-specific types (e.g. `MyStruct<u8>`)
- // over less-specific types (e.g. `Option<MyStruct<u8>>`)
- if self.depth >= self.cause_depth {
- self.cause = Some(error.obligation.cause);
- self.cause_depth = self.depth
- }
+ let infcx = self.tcx.infer_ctxt().build();
+ let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
+ let cause = traits::ObligationCause::new(
+ ty.span,
+ self.hir_id,
+ traits::ObligationCauseCode::WellFormed(None),
+ );
+ let errors = traits::fully_solve_obligation(
+ &infcx,
+ traits::Obligation::new(
+ cause,
+ self.param_env,
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into()))
+ .to_predicate(self.tcx),
+ ),
+ );
+ if !errors.is_empty() {
+ debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
+ for error in errors {
+ if error.obligation.predicate == self.predicate {
+ // Save the cause from the greatest depth - this corresponds
+ // to picking more-specific types (e.g. `MyStruct<u8>`)
+ // over less-specific types (e.g. `Option<MyStruct<u8>>`)
+ if self.depth >= self.cause_depth {
+ self.cause = Some(error.obligation.cause);
+ self.cause_depth = self.depth
}
}
}
- });
+ }
self.depth += 1;
intravisit::walk_ty(self, ty);
self.depth -= 1;
@@ -119,7 +117,7 @@ fn diagnostic_hir_wf_check<'tcx>(
let ty = match loc {
WellFormedLoc::Ty(_) => match hir.get(hir_id) {
hir::Node::ImplItem(item) => match item.kind {
- hir::ImplItemKind::TyAlias(ty) => Some(ty),
+ hir::ImplItemKind::Type(ty) => Some(ty),
hir::ImplItemKind::Const(ty, _) => Some(ty),
ref item => bug!("Unexpected ImplItem {:?}", item),
},
diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index 9fee1eaae..136f61999 100644
--- a/compiler/rustc_typeck/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -11,7 +11,7 @@
use crate::constrained_generic_params as cgp;
use min_specialization::check_min_specialization;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
@@ -19,8 +19,6 @@ use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
use rustc_span::{Span, Symbol};
-use std::collections::hash_map::Entry::{Occupied, Vacant};
-
mod min_specialization;
/// Checks that all the type/lifetime parameters on an impl also
@@ -57,11 +55,10 @@ fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
let min_specialization = tcx.features().min_specialization;
let module = tcx.hir_module_items(module_def_id);
for id in module.items() {
- if matches!(tcx.def_kind(id.def_id), DefKind::Impl) {
- enforce_impl_params_are_constrained(tcx, id.def_id);
- enforce_impl_items_are_distinct(tcx, id.def_id);
+ if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
+ enforce_impl_params_are_constrained(tcx, id.owner_id.def_id);
if min_specialization {
- check_min_specialization(tcx, id.def_id);
+ check_min_specialization(tcx, id.owner_id.def_id);
}
}
}
@@ -194,35 +191,3 @@ fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol
}
err.emit();
}
-
-/// Enforce that we do not have two items in an impl with the same name.
-fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
- let mut seen_type_items = FxHashMap::default();
- let mut seen_value_items = FxHashMap::default();
- for &impl_item_ref in tcx.associated_item_def_ids(impl_def_id) {
- let impl_item = tcx.associated_item(impl_item_ref);
- let seen_items = match impl_item.kind {
- ty::AssocKind::Type => &mut seen_type_items,
- _ => &mut seen_value_items,
- };
- let span = tcx.def_span(impl_item_ref);
- let ident = impl_item.ident(tcx);
- match seen_items.entry(ident.normalize_to_macros_2_0()) {
- Occupied(entry) => {
- let mut err = struct_span_err!(
- tcx.sess,
- span,
- E0201,
- "duplicate definitions with name `{}`:",
- ident
- );
- err.span_label(*entry.get(), format!("previous definition of `{}` here", ident));
- err.span_label(span, "duplicate definition");
- err.emit();
- }
- Vacant(entry) => {
- entry.insert(span);
- }
- }
- }
-}
diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 2741d9f77..e806e9487 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -77,7 +77,7 @@ use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
use rustc_span::Span;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
+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};
@@ -130,8 +130,10 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
///
/// Example
///
+/// ```ignore (illustrative)
/// impl<A, B> Foo<A> for B { /* impl2 */ }
/// impl<C> Foo<Vec<C>> for C { /* impl1 */ }
+/// ```
///
/// Would return `S1 = [C]` and `S2 = [Vec<C>, C]`.
fn get_impl_substs<'tcx>(
@@ -139,34 +141,33 @@ fn get_impl_substs<'tcx>(
impl1_def_id: LocalDefId,
impl2_node: Node,
) -> Option<(SubstsRef<'tcx>, SubstsRef<'tcx>)> {
- tcx.infer_ctxt().enter(|ref infcx| {
- let ocx = ObligationCtxt::new(infcx);
- let param_env = tcx.param_env(impl1_def_id);
- let impl1_hir_id = tcx.hir().local_def_id_to_hir_id(impl1_def_id);
+ let infcx = &tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(infcx);
+ let param_env = tcx.param_env(impl1_def_id);
+ let impl1_hir_id = tcx.hir().local_def_id_to_hir_id(impl1_def_id);
- let assumed_wf_types =
- ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
+ let assumed_wf_types =
+ 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.to_def_id());
- let impl2_substs =
- translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
+ let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id());
+ let impl2_substs =
+ translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- ocx.infcx.report_fulfillment_errors(&errors, None, false);
- return None;
- }
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ ocx.infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ return None;
+ }
- let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types);
- let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
- infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
- let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
- let span = tcx.def_span(impl1_def_id);
- tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
- return None;
- };
- Some((impl1_substs, impl2_substs))
- })
+ let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types);
+ let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
+ infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
+ let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
+ let span = tcx.def_span(impl1_def_id);
+ tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
+ return None;
+ };
+ Some((impl1_substs, impl2_substs))
}
/// Returns a list of all of the unconstrained subst of the given impl.
@@ -226,13 +227,17 @@ fn unconstrained_parent_impl_substs<'tcx>(
///
/// For example forbid the following:
///
+/// ```ignore (illustrative)
/// impl<A> Tr for A { }
/// impl<B> Tr for (B, B) { }
+/// ```
///
/// Note that only consider the unconstrained parameters of the base impl:
///
+/// ```ignore (illustrative)
/// impl<S, I: IntoIterator<Item = S>> Tr<S> for I { }
/// impl<T> Tr<T> for Vec<T> { }
+/// ```
///
/// The substs for the parent impl here are `[T, Vec<T>]`, which repeats `T`,
/// but `S` is constrained in the parent impl, so `parent_substs` is only
@@ -257,8 +262,10 @@ fn check_duplicate_params<'tcx>(
///
/// For example forbid the following:
///
+/// ```ignore (illustrative)
/// impl<A> Tr for A { }
/// impl Tr for &'static i32 { }
+/// ```
fn check_static_lifetimes<'tcx>(
tcx: TyCtxt<'tcx>,
parent_substs: &Vec<GenericArg<'tcx>>,
@@ -344,23 +351,21 @@ fn check_predicates<'tcx>(
// Include the well-formed predicates of the type parameters of the impl.
for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
- tcx.infer_ctxt().enter(|ref infcx| {
- let obligations = wf::obligations(
- infcx,
- tcx.param_env(impl1_def_id),
- tcx.hir().local_def_id_to_hir_id(impl1_def_id),
- 0,
- arg,
- span,
- )
- .unwrap();
+ let infcx = &tcx.infer_ctxt().build();
+ let obligations = wf::obligations(
+ infcx,
+ tcx.param_env(impl1_def_id),
+ tcx.hir().local_def_id_to_hir_id(impl1_def_id),
+ 0,
+ arg,
+ span,
+ )
+ .unwrap();
- assert!(!obligations.needs_infer());
- impl2_predicates.extend(
- traits::elaborate_obligations(tcx, obligations)
- .map(|obligation| obligation.predicate),
- )
- })
+ assert!(!obligations.needs_infer());
+ impl2_predicates.extend(
+ traits::elaborate_obligations(tcx, obligations).map(|obligation| obligation.predicate),
+ )
}
impl2_predicates.extend(
traits::elaborate_predicates_with_span(tcx, always_applicable_traits)
@@ -423,13 +428,10 @@ fn trait_predicate_kind<'tcx>(
predicate: ty::Predicate<'tcx>,
) -> Option<TraitSpecializationKind> {
match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(ty::TraitPredicate {
- trait_ref,
- constness: ty::BoundConstness::NotConst,
- polarity: _,
- }) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
- ty::PredicateKind::Trait(_)
- | ty::PredicateKind::RegionOutlives(_)
+ ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _ }) => {
+ Some(tcx.trait_def(trait_ref.def_id).specialization_kind)
+ }
+ ty::PredicateKind::RegionOutlives(_)
| ty::PredicateKind::TypeOutlives(_)
| ty::PredicateKind::Projection(_)
| ty::PredicateKind::WellFormed(_)
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index b1ce972e1..525cd2419 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -64,15 +64,13 @@ This API is completely unstable and subject to change.
#![feature(if_let_guard)]
#![feature(is_sorted)]
#![feature(iter_intersperse)]
-#![cfg_attr(bootstrap, feature(label_break_value))]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(once_cell)]
#![feature(slice_partition_dedup)]
#![feature(try_blocks)]
-#![feature(is_some_with)]
+#![feature(is_some_and)]
#![feature(type_alias_impl_trait)]
#![recursion_limit = "256"]
@@ -84,20 +82,19 @@ extern crate rustc_middle;
// These are used by Clippy.
pub mod check;
-pub mod expr_use_visitor;
-mod astconv;
+pub mod astconv;
mod bounds;
mod check_unused;
mod coherence;
-mod collect;
+// FIXME: This module shouldn't be public.
+pub mod collect;
mod constrained_generic_params;
mod errors;
pub mod hir_wf_check;
mod impl_wf_check;
-mod mem_categorization;
mod outlives;
-mod structured_errors;
+pub mod structured_errors;
mod variance;
use rustc_errors::{struct_span_err, ErrorGuaranteed};
@@ -112,7 +109,7 @@ use rustc_middle::util;
use rustc_session::config::EntryFnType;
use rustc_span::{symbol::sym, Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
use std::iter;
@@ -143,24 +140,23 @@ fn require_same_types<'tcx>(
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> bool {
- tcx.infer_ctxt().enter(|ref infcx| {
- let param_env = ty::ParamEnv::empty();
- let errors = match infcx.at(cause, param_env).eq(expected, actual) {
- Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
- Err(err) => {
- infcx.report_mismatched_types(cause, expected, actual, err).emit();
- return false;
- }
- };
+ let infcx = &tcx.infer_ctxt().build();
+ let param_env = ty::ParamEnv::empty();
+ let errors = match infcx.at(cause, param_env).eq(expected, actual) {
+ Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
+ Err(err) => {
+ infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit();
+ return false;
+ }
+ };
- match &errors[..] {
- [] => true,
- errors => {
- infcx.report_fulfillment_errors(errors, None, false);
- false
- }
+ match &errors[..] {
+ [] => true,
+ errors => {
+ infcx.err_ctxt().report_fulfillment_errors(errors, None, false);
+ false
}
- })
+ }
}
fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
@@ -307,23 +303,22 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
error = true;
}
let return_ty = return_ty.skip_binder();
- tcx.infer_ctxt().enter(|infcx| {
- // Main should have no WC, so empty param env is OK here.
- let param_env = ty::ParamEnv::empty();
- let cause = traits::ObligationCause::new(
- return_ty_span,
- main_diagnostics_hir_id,
- ObligationCauseCode::MainFunctionType,
- );
- let ocx = traits::ObligationCtxt::new(&infcx);
- let norm_return_ty = ocx.normalize(cause.clone(), param_env, return_ty);
- ocx.register_bound(cause, param_env, norm_return_ty, term_did);
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- error = true;
- }
- });
+ let infcx = tcx.infer_ctxt().build();
+ // Main should have no WC, so empty param env is OK here.
+ let param_env = ty::ParamEnv::empty();
+ let cause = traits::ObligationCause::new(
+ return_ty_span,
+ main_diagnostics_hir_id,
+ ObligationCauseCode::MainFunctionType,
+ );
+ let ocx = traits::ObligationCtxt::new(&infcx);
+ let norm_return_ty = ocx.normalize(cause.clone(), param_env, return_ty);
+ ocx.register_bound(cause, param_env, norm_return_ty, term_did);
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ error = true;
+ }
// now we can take the return type of the given main function
expected_return_type = main_fnsig.output();
} else {
@@ -386,7 +381,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
error = true;
}
if let hir::IsAsync::Async = sig.header.asyncness {
- let span = tcx.def_span(it.def_id);
+ let span = tcx.def_span(it.owner_id);
struct_span_err!(
tcx.sess,
span,
diff --git a/compiler/rustc_typeck/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index 7534482cc..7534482cc 100644
--- a/compiler/rustc_typeck/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index 3b779280e..90c6edb65 100644
--- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -1,8 +1,8 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
+use rustc_middle::ty::{GenericArg, GenericArgKind};
use rustc_span::Span;
use super::explicit::ExplicitPredicatesMap;
@@ -29,7 +29,7 @@ pub(super) fn infer_predicates<'tcx>(
// Visit all the crates and infer predicates
for id in tcx.hir().items() {
- let item_did = id.def_id;
+ let item_did = id.owner_id;
debug!("InferVisitor::visit_item(item={:?})", item_did);
diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs
index e50c26765..e50c26765 100644
--- a/compiler/rustc_typeck/src/outlives/mod.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs
diff --git a/compiler/rustc_typeck/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs
index eb0e12034..fa2ac5659 100644
--- a/compiler/rustc_typeck/src/outlives/test.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/test.rs
@@ -6,11 +6,11 @@ pub fn test_inferred_outlives(tcx: TyCtxt<'_>) {
for id in tcx.hir().items() {
// For unit testing: check for a special "rustc_outlives"
// attribute and report an error with various results if found.
- if tcx.has_attr(id.def_id.to_def_id(), sym::rustc_outlives) {
- let inferred_outlives_of = tcx.inferred_outlives_of(id.def_id);
+ if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_outlives) {
+ let inferred_outlives_of = tcx.inferred_outlives_of(id.owner_id);
struct_span_err!(
tcx.sess,
- tcx.def_span(id.def_id),
+ tcx.def_span(id.owner_id),
E0640,
"{:?}",
inferred_outlives_of
diff --git a/compiler/rustc_typeck/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs
index 3e8d023fb..0409c7081 100644
--- a/compiler/rustc_typeck/src/outlives/utils.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs
@@ -96,6 +96,23 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
.or_insert(span);
}
+ Component::Opaque(def_id, substs) => {
+ // This would arise from something like:
+ //
+ // ```rust
+ // type Opaque<T> = impl Sized;
+ // fn defining<T>() -> Opaque<T> {}
+ // struct Ss<'a, T>(&'a Opaque<T>);
+ // ```
+ //
+ // Here we want to have an implied bound `Opaque<T>: 'a`
+
+ let ty = tcx.mk_opaque(def_id, substs);
+ required_predicates
+ .entry(ty::OutlivesPredicate(ty.into(), outlived_region))
+ .or_insert(span);
+ }
+
Component::EscapingProjection(_) => {
// As above, but the projection involves
// late-bound regions. Therefore, the WF
diff --git a/compiler/rustc_typeck/src/structured_errors.rs b/compiler/rustc_hir_analysis/src/structured_errors.rs
index 0b46fce17..0b46fce17 100644
--- a/compiler/rustc_typeck/src/structured_errors.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors.rs
diff --git a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
index 324df313e..324df313e 100644
--- a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
diff --git a/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
index bb6088054..bb6088054 100644
--- a/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
index 435912464..435912464 100644
--- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index eaf0310d5..eaf0310d5 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
diff --git a/compiler/rustc_typeck/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 82103c5a0..82103c5a0 100644
--- a/compiler/rustc_typeck/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
diff --git a/compiler/rustc_typeck/src/variance/solve.rs b/compiler/rustc_hir_analysis/src/variance/solve.rs
index 97aca621a..97aca621a 100644
--- a/compiler/rustc_typeck/src/variance/solve.rs
+++ b/compiler/rustc_hir_analysis/src/variance/solve.rs
diff --git a/compiler/rustc_typeck/src/variance/terms.rs b/compiler/rustc_hir_analysis/src/variance/terms.rs
index 1f763011e..1f763011e 100644
--- a/compiler/rustc_typeck/src/variance/terms.rs
+++ b/compiler/rustc_hir_analysis/src/variance/terms.rs
diff --git a/compiler/rustc_typeck/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs
index 2ba87db88..83ed3e44b 100644
--- a/compiler/rustc_typeck/src/variance/test.rs
+++ b/compiler/rustc_hir_analysis/src/variance/test.rs
@@ -6,9 +6,10 @@ pub fn test_variance(tcx: TyCtxt<'_>) {
// For unit testing: check for a special "rustc_variance"
// attribute and report an error with various results if found.
for id in tcx.hir().items() {
- if tcx.has_attr(id.def_id.to_def_id(), sym::rustc_variance) {
- let variances_of = tcx.variances_of(id.def_id);
- struct_span_err!(tcx.sess, tcx.def_span(id.def_id), E0208, "{:?}", variances_of).emit();
+ if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_variance) {
+ let variances_of = tcx.variances_of(id.owner_id);
+ struct_span_err!(tcx.sess, tcx.def_span(id.owner_id), E0208, "{:?}", variances_of)
+ .emit();
}
}
}
diff --git a/compiler/rustc_typeck/src/variance/xform.rs b/compiler/rustc_hir_analysis/src/variance/xform.rs
index 027f0859f..027f0859f 100644
--- a/compiler/rustc_typeck/src/variance/xform.rs
+++ b/compiler/rustc_hir_analysis/src/variance/xform.rs
diff --git a/compiler/rustc_hir_pretty/Cargo.toml b/compiler/rustc_hir_pretty/Cargo.toml
index 46a8e7dee..1ea7be1ae 100644
--- a/compiler/rustc_hir_pretty/Cargo.toml
+++ b/compiler/rustc_hir_pretty/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 35a58296e..da27554a2 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -887,7 +887,7 @@ impl<'a> State<'a> {
self.end(); // need to close a box
self.ann.nested(self, Nested::Body(body));
}
- hir::ImplItemKind::TyAlias(ty) => {
+ hir::ImplItemKind::Type(ty) => {
self.print_associated_type(ii.ident, ii.generics, None, Some(ty));
}
}
@@ -1687,7 +1687,11 @@ impl<'a> State<'a> {
let mut nonelided_generic_args: bool = false;
let elide_lifetimes = generic_args.args.iter().all(|arg| match arg {
- GenericArg::Lifetime(lt) => lt.is_elided(),
+ GenericArg::Lifetime(lt) if lt.is_elided() => true,
+ GenericArg::Lifetime(_) => {
+ nonelided_generic_args = true;
+ false
+ }
_ => {
nonelided_generic_args = true;
true
diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml
new file mode 100644
index 000000000..093f9bb84
--- /dev/null
+++ b/compiler/rustc_hir_typeck/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "rustc_hir_typeck"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
+tracing = "0.1"
+rustc_ast = { path = "../rustc_ast" }
+rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_errors = { path = "../rustc_errors" }
+rustc_graphviz = { path = "../rustc_graphviz" }
+rustc_index = { path = "../rustc_index" }
+rustc_infer = { path = "../rustc_infer" }
+rustc_hir = { path = "../rustc_hir" }
+rustc_hir_analysis = { path = "../rustc_hir_analysis" }
+rustc_hir_pretty = { path = "../rustc_hir_pretty" }
+rustc_lint = { path = "../rustc_lint" }
+rustc_middle = { path = "../rustc_middle" }
+rustc_macros = { path = "../rustc_macros" }
+rustc_serialize = { path = "../rustc_serialize" }
+rustc_session = { path = "../rustc_session" }
+rustc_span = { path = "../rustc_span" }
+rustc_target = { path = "../rustc_target" }
+rustc_trait_selection = { path = "../rustc_trait_selection" }
+rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 20332e75c..2b15d4dcd 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -1,10 +1,10 @@
-use crate::check::coercion::{AsCoercionSite, CoerceMany};
-use crate::check::{Diverges, Expectation, FnCtxt, Needs};
+use crate::coercion::{AsCoercionSite, CoerceMany};
+use crate::{Diverges, Expectation, FnCtxt, Needs};
use rustc_errors::{Applicability, MultiSpan};
use rustc_hir::{self as hir, ExprKind};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::traits::Obligation;
-use rustc_middle::ty::{self, Subst, ToPredicate, Ty};
+use rustc_middle::ty::{self, ToPredicate, Ty};
use rustc_span::Span;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{
@@ -140,7 +140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some(ret) = self
.tcx
.hir()
- .find_by_def_id(self.body_id.owner)
+ .find_by_def_id(self.body_id.owner.def_id)
.and_then(|owner| owner.fn_decl())
.map(|decl| decl.output.span())
else { return; };
@@ -259,7 +259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.help("consider adding an `else` block that evaluates to the expected type");
error = true;
},
- ret_reason.is_none(),
+ false,
);
error
}
@@ -495,7 +495,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.typeck_results
.borrow()
.liberated_fn_sigs()
- .get(hir::HirId::make_owner(self.body_id.owner))?;
+ .get(hir::HirId::make_owner(self.body_id.owner.def_id))?;
let substs = sig.output().walk().find_map(|arg| {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
@@ -514,8 +514,11 @@ 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).transpose_iter() {
- let pred = pred.map_bound(|(pred, _)| *pred).subst(self.tcx, substs);
+ for (pred, _) in self
+ .tcx
+ .bound_explicit_item_bounds(rpit_def_id)
+ .subst_iter_copied(self.tcx, substs)
+ {
let pred = match pred.kind().skip_binder() {
ty::PredicateKind::Trait(mut trait_pred) => {
assert_eq!(trait_pred.trait_ref.self_ty(), opaque_ty);
diff --git a/compiler/rustc_typeck/src/check/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs
index 59c366ad7..59c366ad7 100644
--- a/compiler/rustc_typeck/src/check/autoderef.rs
+++ b/compiler/rustc_hir_typeck/src/autoderef.rs
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 0d35c2479..1b33f2f02 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -1,8 +1,10 @@
+use super::method::probe::{IsSuggestion, Mode, ProbeScope};
use super::method::MethodCallee;
-use super::{DefIdOrName, Expectation, FnCtxt, TupleArgumentsFlag};
-use crate::type_error_struct;
+use super::{Expectation, FnCtxt, TupleArgumentsFlag};
-use rustc_errors::{struct_span_err, Applicability, Diagnostic};
+use crate::type_error_struct;
+use rustc_ast::util::parser::PREC_POSTFIX;
+use rustc_errors::{struct_span_err, Applicability, Diagnostic, StashKey};
use rustc_hir as hir;
use rustc_hir::def::{self, Namespace, Res};
use rustc_hir::def_id::DefId;
@@ -17,7 +19,7 @@ use rustc_infer::{
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
};
-use rustc_middle::ty::subst::{Subst, SubstsRef};
+use rustc_middle::ty::SubstsRef;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::{sym, Ident};
@@ -25,6 +27,7 @@ use rustc_span::Span;
use rustc_target::spec::abi;
use rustc_trait_selection::autoderef::Autoderef;
use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::DefIdOrName;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use std::iter;
@@ -60,6 +63,7 @@ pub fn check_legal_trait_for_method_call(
}
}
+#[derive(Debug)]
enum CallStep<'tcx> {
Builtin(Ty<'tcx>),
DeferredClosure(LocalDefId, ty::FnSig<'tcx>),
@@ -188,6 +192,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None;
}
+ ty::Error(_) => {
+ return None;
+ }
+
_ => {}
}
@@ -394,140 +402,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
ty::FnPtr(sig) => (sig, None),
_ => {
- let mut unit_variant = None;
- if let hir::ExprKind::Path(qpath) = &callee_expr.kind
- && let Res::Def(def::DefKind::Ctor(kind, def::CtorKind::Const), _)
- = self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
- // Only suggest removing parens if there are no arguments
- && arg_exprs.is_empty()
+ if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = &callee_expr.kind
+ && let [segment] = path.segments
+ && let Some(mut diag) = self
+ .tcx
+ .sess
+ .diagnostic()
+ .steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod)
{
- let descr = match kind {
- def::CtorOf::Struct => "struct",
- def::CtorOf::Variant => "enum variant",
- };
- let removal_span =
- callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
- unit_variant =
- Some((removal_span, descr, rustc_hir_pretty::qpath_to_string(qpath)));
- }
-
- let callee_ty = self.resolve_vars_if_possible(callee_ty);
- let mut err = type_error_struct!(
- self.tcx.sess,
- callee_expr.span,
- callee_ty,
- E0618,
- "expected function, found {}",
- match &unit_variant {
- Some((_, kind, path)) => format!("{kind} `{path}`"),
- None => format!("`{callee_ty}`"),
- }
- );
-
- self.identify_bad_closure_def_and_call(
- &mut err,
- call_expr.hir_id,
- &callee_expr.kind,
- callee_expr.span,
- );
-
- if let Some((removal_span, kind, path)) = &unit_variant {
- err.span_suggestion_verbose(
- *removal_span,
- &format!(
- "`{path}` is a unit {kind}, and does not take parentheses to be constructed",
- ),
- "",
- Applicability::MachineApplicable,
- );
- }
-
- let mut inner_callee_path = None;
- let def = match callee_expr.kind {
- hir::ExprKind::Path(ref qpath) => {
- self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
- }
- hir::ExprKind::Call(ref inner_callee, _) => {
- // If the call spans more than one line and the callee kind is
- // itself another `ExprCall`, that's a clue that we might just be
- // missing a semicolon (Issue #51055)
- let call_is_multiline =
- self.tcx.sess.source_map().is_multiline(call_expr.span);
- if call_is_multiline {
- err.span_suggestion(
- callee_expr.span.shrink_to_hi(),
- "consider using a semicolon here",
- ";",
- Applicability::MaybeIncorrect,
- );
- }
- if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.kind {
- inner_callee_path = Some(inner_qpath);
- self.typeck_results.borrow().qpath_res(inner_qpath, inner_callee.hir_id)
- } else {
- Res::Err
- }
- }
- _ => Res::Err,
- };
-
- if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
- if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_expr, callee_ty)
- && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
+ // Try suggesting `foo(a)` -> `a.foo()` if possible.
+ if let Some(ty) =
+ self.suggest_call_as_method(
+ &mut diag,
+ segment,
+ arg_exprs,
+ call_expr,
+ expected
+ )
{
- let descr = match maybe_def {
- DefIdOrName::DefId(def_id) => self.tcx.def_kind(def_id).descr(def_id),
- DefIdOrName::Name(name) => name,
- };
- err.span_label(
- callee_expr.span,
- format!("this {descr} returns an unsized value `{output_ty}`, so it cannot be called")
- );
- if let DefIdOrName::DefId(def_id) = maybe_def
- && let Some(def_span) = self.tcx.hir().span_if_local(def_id)
- {
- err.span_label(def_span, "the callable type is defined here");
- }
+ diag.emit();
+ return ty;
} else {
- err.span_label(call_expr.span, "call expression requires function");
+ diag.emit();
}
}
- if let Some(span) = self.tcx.hir().res_span(def) {
- let callee_ty = callee_ty.to_string();
- let label = match (unit_variant, inner_callee_path) {
- (Some((_, kind, path)), _) => Some(format!("{kind} `{path}` defined here")),
- (_, Some(hir::QPath::Resolved(_, path))) => self
- .tcx
- .sess
- .source_map()
- .span_to_snippet(path.span)
- .ok()
- .map(|p| format!("`{p}` defined here returns `{callee_ty}`")),
- _ => {
- match def {
- // Emit a different diagnostic for local variables, as they are not
- // type definitions themselves, but rather variables *of* that type.
- Res::Local(hir_id) => Some(format!(
- "`{}` has type `{}`",
- self.tcx.hir().name(hir_id),
- callee_ty
- )),
- Res::Def(kind, def_id) if kind.ns() == Some(Namespace::ValueNS) => {
- Some(format!(
- "`{}` defined here",
- self.tcx.def_path_str(def_id),
- ))
- }
- _ => Some(format!("`{callee_ty}` defined here")),
- }
- }
- };
- if let Some(label) = label {
- err.span_label(span, label);
- }
- }
- err.emit();
+ self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs);
// This is the "default" function signature, used in case of error.
// In that case, we check each argument against "error" in order to
@@ -574,6 +474,243 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn_sig.output()
}
+ /// Attempts to reinterpret `method(rcvr, args...)` as `rcvr.method(args...)`
+ /// and suggesting the fix if the method probe is successful.
+ fn suggest_call_as_method(
+ &self,
+ diag: &mut Diagnostic,
+ segment: &'tcx hir::PathSegment<'tcx>,
+ arg_exprs: &'tcx [hir::Expr<'tcx>],
+ call_expr: &'tcx hir::Expr<'tcx>,
+ expected: Expectation<'tcx>,
+ ) -> Option<Ty<'tcx>> {
+ if let [callee_expr, rest @ ..] = arg_exprs {
+ let callee_ty = self.check_expr(callee_expr);
+ // First, do a probe with `IsSuggestion(true)` to avoid emitting
+ // any strange errors. If it's successful, then we'll do a true
+ // method lookup.
+ let Ok(pick) = self
+ .probe_for_name(
+ call_expr.span,
+ Mode::MethodCall,
+ segment.ident,
+ IsSuggestion(true),
+ callee_ty,
+ call_expr.hir_id,
+ // We didn't record the in scope traits during late resolution
+ // so we need to probe AllTraits unfortunately
+ ProbeScope::AllTraits,
+ ) else {
+ return None;
+ };
+
+ let pick = self.confirm_method(
+ call_expr.span,
+ callee_expr,
+ call_expr,
+ callee_ty,
+ pick,
+ segment,
+ );
+ if pick.illegal_sized_bound.is_some() {
+ return None;
+ }
+
+ let up_to_rcvr_span = segment.ident.span.until(callee_expr.span);
+ let rest_span = callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
+ let rest_snippet = if let Some(first) = rest.first() {
+ self.tcx
+ .sess
+ .source_map()
+ .span_to_snippet(first.span.to(call_expr.span.shrink_to_hi()))
+ } else {
+ Ok(")".to_string())
+ };
+
+ if let Ok(rest_snippet) = rest_snippet {
+ let sugg = if callee_expr.precedence().order() >= PREC_POSTFIX {
+ vec![
+ (up_to_rcvr_span, "".to_string()),
+ (rest_span, format!(".{}({rest_snippet}", segment.ident)),
+ ]
+ } else {
+ vec![
+ (up_to_rcvr_span, "(".to_string()),
+ (rest_span, format!(").{}({rest_snippet}", segment.ident)),
+ ]
+ };
+ let self_ty = self.resolve_vars_if_possible(pick.callee.sig.inputs()[0]);
+ diag.multipart_suggestion(
+ format!(
+ "use the `.` operator to call the method `{}{}` on `{self_ty}`",
+ self.tcx
+ .associated_item(pick.callee.def_id)
+ .trait_container(self.tcx)
+ .map_or_else(
+ || String::new(),
+ |trait_def_id| self.tcx.def_path_str(trait_def_id) + "::"
+ ),
+ segment.ident
+ ),
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+
+ // Let's check the method fully now
+ let return_ty = self.check_method_argument_types(
+ segment.ident.span,
+ call_expr,
+ Ok(pick.callee),
+ rest,
+ TupleArgumentsFlag::DontTupleArguments,
+ expected,
+ );
+
+ return Some(return_ty);
+ }
+ }
+
+ None
+ }
+
+ fn report_invalid_callee(
+ &self,
+ call_expr: &'tcx hir::Expr<'tcx>,
+ callee_expr: &'tcx hir::Expr<'tcx>,
+ callee_ty: Ty<'tcx>,
+ arg_exprs: &'tcx [hir::Expr<'tcx>],
+ ) {
+ let mut unit_variant = None;
+ if let hir::ExprKind::Path(qpath) = &callee_expr.kind
+ && let Res::Def(def::DefKind::Ctor(kind, def::CtorKind::Const), _)
+ = self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
+ // Only suggest removing parens if there are no arguments
+ && arg_exprs.is_empty()
+ {
+ let descr = match kind {
+ def::CtorOf::Struct => "struct",
+ def::CtorOf::Variant => "enum variant",
+ };
+ let removal_span = callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
+ unit_variant = Some((removal_span, descr, rustc_hir_pretty::qpath_to_string(qpath)));
+ }
+
+ let callee_ty = self.resolve_vars_if_possible(callee_ty);
+ let mut err = type_error_struct!(
+ self.tcx.sess,
+ callee_expr.span,
+ callee_ty,
+ E0618,
+ "expected function, found {}",
+ match &unit_variant {
+ Some((_, kind, path)) => format!("{kind} `{path}`"),
+ None => format!("`{callee_ty}`"),
+ }
+ );
+
+ self.identify_bad_closure_def_and_call(
+ &mut err,
+ call_expr.hir_id,
+ &callee_expr.kind,
+ callee_expr.span,
+ );
+
+ if let Some((removal_span, kind, path)) = &unit_variant {
+ err.span_suggestion_verbose(
+ *removal_span,
+ &format!(
+ "`{path}` is a unit {kind}, and does not take parentheses to be constructed",
+ ),
+ "",
+ Applicability::MachineApplicable,
+ );
+ }
+
+ let mut inner_callee_path = None;
+ let def = match callee_expr.kind {
+ hir::ExprKind::Path(ref qpath) => {
+ self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
+ }
+ hir::ExprKind::Call(ref inner_callee, _) => {
+ // If the call spans more than one line and the callee kind is
+ // itself another `ExprCall`, that's a clue that we might just be
+ // missing a semicolon (Issue #51055)
+ let call_is_multiline = self.tcx.sess.source_map().is_multiline(call_expr.span);
+ if call_is_multiline {
+ err.span_suggestion(
+ callee_expr.span.shrink_to_hi(),
+ "consider using a semicolon here",
+ ";",
+ Applicability::MaybeIncorrect,
+ );
+ }
+ if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.kind {
+ inner_callee_path = Some(inner_qpath);
+ self.typeck_results.borrow().qpath_res(inner_qpath, inner_callee.hir_id)
+ } else {
+ Res::Err
+ }
+ }
+ _ => Res::Err,
+ };
+
+ if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
+ if let Some((maybe_def, output_ty, _)) =
+ self.extract_callable_info(callee_expr, callee_ty)
+ && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
+ {
+ let descr = match maybe_def {
+ DefIdOrName::DefId(def_id) => self.tcx.def_kind(def_id).descr(def_id),
+ DefIdOrName::Name(name) => name,
+ };
+ err.span_label(
+ callee_expr.span,
+ format!("this {descr} returns an unsized value `{output_ty}`, so it cannot be called")
+ );
+ if let DefIdOrName::DefId(def_id) = maybe_def
+ && let Some(def_span) = self.tcx.hir().span_if_local(def_id)
+ {
+ err.span_label(def_span, "the callable type is defined here");
+ }
+ } else {
+ err.span_label(call_expr.span, "call expression requires function");
+ }
+ }
+
+ if let Some(span) = self.tcx.hir().res_span(def) {
+ let callee_ty = callee_ty.to_string();
+ let label = match (unit_variant, inner_callee_path) {
+ (Some((_, kind, path)), _) => Some(format!("{kind} `{path}` defined here")),
+ (_, Some(hir::QPath::Resolved(_, path))) => self
+ .tcx
+ .sess
+ .source_map()
+ .span_to_snippet(path.span)
+ .ok()
+ .map(|p| format!("`{p}` defined here returns `{callee_ty}`")),
+ _ => {
+ match def {
+ // Emit a different diagnostic for local variables, as they are not
+ // type definitions themselves, but rather variables *of* that type.
+ Res::Local(hir_id) => Some(format!(
+ "`{}` has type `{}`",
+ self.tcx.hir().name(hir_id),
+ callee_ty
+ )),
+ Res::Def(kind, def_id) if kind.ns() == Some(Namespace::ValueNS) => {
+ Some(format!("`{}` defined here", self.tcx.def_path_str(def_id),))
+ }
+ _ => Some(format!("`{callee_ty}` defined here")),
+ }
+ }
+ };
+ if let Some(label) = label {
+ err.span_label(span, label);
+ }
+ }
+ err.emit();
+ }
+
fn confirm_deferred_closure_call(
&self,
call_expr: &'tcx hir::Expr<'tcx>,
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 81a979865..d1dab0540 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -30,20 +30,18 @@
use super::FnCtxt;
-use crate::hir::def_id::DefId;
use crate::type_error_struct;
-use hir::def_id::LOCAL_CRATE;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
-use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
use rustc_middle::mir::Mutability;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::cast::{CastKind, CastTy};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Binder, Ty, TypeAndMut, TypeVisitable, VariantDef};
+use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
use rustc_session::lint;
use rustc_session::Session;
+use rustc_span::def_id::{DefId, LOCAL_CRATE};
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
@@ -62,6 +60,8 @@ pub struct CastCheck<'tcx> {
cast_ty: Ty<'tcx>,
cast_span: Span,
span: Span,
+ /// whether the cast is made in a const context or not.
+ pub constness: hir::Constness,
}
/// The kind of pointer and associated metadata (thin, length or vtable) - we
@@ -204,85 +204,18 @@ fn make_invalid_casting_error<'a, 'tcx>(
)
}
-pub enum CastCheckResult<'tcx> {
- Ok,
- Deferred(CastCheck<'tcx>),
- Err(ErrorGuaranteed),
-}
-
-pub fn check_cast<'tcx>(
- fcx: &FnCtxt<'_, 'tcx>,
- expr: &'tcx hir::Expr<'tcx>,
- expr_ty: Ty<'tcx>,
- cast_ty: Ty<'tcx>,
- cast_span: Span,
- span: Span,
-) -> CastCheckResult<'tcx> {
- if cast_ty.is_dyn_star() {
- check_dyn_star_cast(fcx, expr, expr_ty, cast_ty)
- } else {
- match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) {
- Ok(check) => CastCheckResult::Deferred(check),
- Err(e) => CastCheckResult::Err(e),
- }
- }
-}
-
-fn check_dyn_star_cast<'tcx>(
- fcx: &FnCtxt<'_, 'tcx>,
- expr: &'tcx hir::Expr<'tcx>,
- expr_ty: Ty<'tcx>,
- cast_ty: Ty<'tcx>,
-) -> CastCheckResult<'tcx> {
- // Find the bounds in the dyn*. For eaxmple, if we have
- //
- // let x = 22_usize as dyn* (Clone + Debug + 'static)
- //
- // this would return `existential_predicates = [?Self: Clone, ?Self: Debug]` and `region = 'static`.
- let (existential_predicates, region) = match cast_ty.kind() {
- ty::Dynamic(predicates, region, ty::DynStar) => (predicates, region),
- _ => panic!("Invalid dyn* cast_ty"),
- };
-
- let cause = ObligationCause::new(
- expr.span,
- fcx.body_id,
- // FIXME(dyn-star): Use a better obligation cause code
- ObligationCauseCode::MiscObligation,
- );
-
- // For each existential predicate (e.g., `?Self: Clone`) substitute
- // the type of the expression (e.g., `usize` in our example above)
- // and then require that the resulting predicate (e.g., `usize: Clone`)
- // holds (it does).
- for existential_predicate in existential_predicates.iter() {
- let predicate = existential_predicate.with_self_ty(fcx.tcx, expr_ty);
- fcx.register_predicate(Obligation::new(cause.clone(), fcx.param_env, predicate));
- }
-
- // Enforce the region bound `'static` (e.g., `usize: 'static`, in our example).
- fcx.register_predicate(Obligation::new(
- cause,
- fcx.param_env,
- fcx.tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives(
- ty::OutlivesPredicate(expr_ty, *region),
- ))),
- ));
-
- CastCheckResult::Ok
-}
-
impl<'a, 'tcx> CastCheck<'tcx> {
- fn new(
+ pub fn new(
fcx: &FnCtxt<'a, 'tcx>,
expr: &'tcx hir::Expr<'tcx>,
expr_ty: Ty<'tcx>,
cast_ty: Ty<'tcx>,
cast_span: Span,
span: Span,
+ constness: hir::Constness,
) -> Result<CastCheck<'tcx>, ErrorGuaranteed> {
let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span);
- let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span };
+ let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span, constness };
// For better error messages, check for some obviously unsized
// cases now. We do a more thorough check at the end, once
@@ -596,7 +529,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
err.emit();
}
CastError::SizedUnsizedCast => {
- use crate::structured_errors::{SizedUnsizedCast, StructuredDiagnostic};
+ use rustc_hir_analysis::structured_errors::{
+ SizedUnsizedCast, StructuredDiagnostic,
+ };
SizedUnsizedCast {
sess: &fcx.tcx.sess,
@@ -754,19 +689,25 @@ impl<'a, 'tcx> CastCheck<'tcx> {
} else {
("", lint::builtin::TRIVIAL_CASTS)
};
- fcx.tcx.struct_span_lint_hir(lint, self.expr.hir_id, self.span, |err| {
- err.build(&format!(
- "trivial {}cast: `{}` as `{}`",
- adjective,
- fcx.ty_to_string(t_expr),
- fcx.ty_to_string(t_cast)
- ))
- .help(&format!(
- "cast can be replaced by coercion; this might \
- require {type_asc_or}a temporary variable"
- ))
- .emit();
- });
+ fcx.tcx.struct_span_lint_hir(
+ lint,
+ self.expr.hir_id,
+ self.span,
+ DelayDm(|| {
+ format!(
+ "trivial {}cast: `{}` as `{}`",
+ adjective,
+ fcx.ty_to_string(t_expr),
+ fcx.ty_to_string(t_cast)
+ )
+ }),
+ |lint| {
+ lint.help(format!(
+ "cast can be replaced by coercion; this might \
+ require {type_asc_or}a temporary variable"
+ ))
+ },
+ );
}
#[instrument(skip(fcx), level = "debug")]
@@ -928,11 +869,13 @@ impl<'a, 'tcx> CastCheck<'tcx> {
(Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast),
- // FIXME(dyn-star): this needs more conditions...
- (_, DynStar) => Ok(CastKind::DynStarCast),
-
- // FIXME(dyn-star): do we want to allow dyn* upcasting or other casts?
- (DynStar, _) => Err(CastError::IllegalCast),
+ (_, DynStar) | (DynStar, _) => {
+ if fcx.tcx.features().dyn_star {
+ bug!("should be handled by `try_coerce`")
+ } else {
+ Err(CastError::IllegalCast)
+ }
+ }
}
}
@@ -1074,12 +1017,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
lint::builtin::CENUM_IMPL_DROP_CAST,
self.expr.hir_id,
self.span,
- |err| {
- err.build(&format!(
- "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
- self.expr_ty, self.cast_ty
- ))
- .emit();
+ DelayDm(|| format!(
+ "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
+ self.expr_ty, self.cast_ty
+ )),
+ |lint| {
+ lint
},
);
}
@@ -1090,12 +1033,11 @@ impl<'a, 'tcx> CastCheck<'tcx> {
lint::builtin::LOSSY_PROVENANCE_CASTS,
self.expr.hir_id,
self.span,
- |err| {
- let mut err = err.build(&format!(
+ DelayDm(|| format!(
"under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`",
self.expr_ty, self.cast_ty
- ));
-
+ )),
+ |lint| {
let msg = "use `.addr()` to obtain the address of a pointer";
let expr_prec = self.expr.precedence().order();
@@ -1114,9 +1056,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
(cast_span, format!(").addr(){scalar_cast}")),
];
- err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
+ lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
} else {
- err.span_suggestion(
+ lint.span_suggestion(
cast_span,
msg,
format!(".addr(){scalar_cast}"),
@@ -1124,12 +1066,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
);
}
- err.help(
+ lint.help(
"if you can't comply with strict provenance and need to expose the pointer \
provenance you can use `.expose_addr()` instead"
);
- err.emit();
+ lint
},
);
}
@@ -1139,24 +1081,24 @@ impl<'a, 'tcx> CastCheck<'tcx> {
lint::builtin::FUZZY_PROVENANCE_CASTS,
self.expr.hir_id,
self.span,
- |err| {
- let mut err = err.build(&format!(
- "strict provenance disallows casting integer `{}` to pointer `{}`",
- self.expr_ty, self.cast_ty
- ));
+ DelayDm(|| format!(
+ "strict provenance disallows casting integer `{}` to pointer `{}`",
+ self.expr_ty, self.cast_ty
+ )),
+ |lint| {
let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address";
let suggestions = vec![
(self.expr_span.shrink_to_lo(), String::from("(...).with_addr(")),
(self.expr_span.shrink_to_hi().to(self.cast_span), String::from(")")),
];
- err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
- err.help(
+ lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
+ lint.help(
"if you can't comply with strict provenance and don't have a pointer with \
the correct provenance you can use `std::ptr::from_exposed_addr()` instead"
);
- err.emit();
+ lint
},
);
}
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
new file mode 100644
index 000000000..7f76364e1
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -0,0 +1,324 @@
+use crate::coercion::CoerceMany;
+use crate::gather_locals::GatherLocalsVisitor;
+use crate::{FnCtxt, Inherited};
+use crate::{GeneratorTypes, UnsafetyState};
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{ImplicitSelfKind, ItemKind, Node};
+use rustc_hir_analysis::check::fn_maybe_err;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::RegionVariableOrigin;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::def_id::LocalDefId;
+use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits;
+use std::cell::RefCell;
+
+/// Helper used for fns and closures. Does the grungy work of checking a function
+/// body and returns the function context used for that purpose, since in the case of a fn item
+/// there is still a bit more to do.
+///
+/// * ...
+/// * inherited: other fields inherited from the enclosing fn (if any)
+#[instrument(skip(inherited, body), level = "debug")]
+pub(super) fn check_fn<'a, 'tcx>(
+ inherited: &'a Inherited<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ fn_sig: ty::FnSig<'tcx>,
+ decl: &'tcx hir::FnDecl<'tcx>,
+ fn_id: hir::HirId,
+ body: &'tcx hir::Body<'tcx>,
+ can_be_generator: Option<hir::Movability>,
+ return_type_pre_known: bool,
+) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
+ // Create the function context. This is either derived from scratch or,
+ // in the case of closures, based on the outer context.
+ let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
+ fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
+ fcx.return_type_pre_known = return_type_pre_known;
+
+ let tcx = fcx.tcx;
+ let hir = tcx.hir();
+
+ let declared_ret_ty = fn_sig.output();
+
+ let ret_ty =
+ fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
+ declared_ret_ty,
+ body.value.hir_id,
+ decl.output.span(),
+ param_env,
+ ));
+ // If we replaced declared_ret_ty with infer vars, then we must be inferring
+ // an opaque type, so set a flag so we can improve diagnostics.
+ fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
+
+ fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
+
+ let span = body.value.span;
+
+ fn_maybe_err(tcx, span, fn_sig.abi);
+
+ if fn_sig.abi == Abi::RustCall {
+ let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
+
+ let err = || {
+ let item = match tcx.hir().get(fn_id) {
+ Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
+ Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Fn(header, ..), ..
+ }) => Some(header),
+ Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(header, ..),
+ ..
+ }) => Some(header),
+ // Closures are RustCall, but they tuple their arguments, so shouldn't be checked
+ Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
+ node => bug!("Item being checked wasn't a function/closure: {:?}", node),
+ };
+
+ if let Some(header) = item {
+ tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
+ }
+ };
+
+ if fn_sig.inputs().len() != expected_args {
+ err()
+ } else {
+ // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
+ // This will probably require wide-scale changes to support a TupleKind obligation
+ // We can't resolve this without knowing the type of the param
+ if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
+ err()
+ }
+ }
+ }
+
+ if body.generator_kind.is_some() && can_be_generator.is_some() {
+ let yield_ty = fcx
+ .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
+ fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
+
+ // Resume type defaults to `()` if the generator has no argument.
+ let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
+
+ fcx.resume_yield_tys = Some((resume_ty, yield_ty));
+ }
+
+ GatherLocalsVisitor::new(&fcx).visit_body(body);
+
+ // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
+ // (as it's created inside the body itself, not passed in from outside).
+ let maybe_va_list = if fn_sig.c_variadic {
+ let span = body.params.last().unwrap().span;
+ let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
+ let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
+
+ Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()]))
+ } else {
+ None
+ };
+
+ // Add formal parameters.
+ let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
+ let inputs_fn = fn_sig.inputs().iter().copied();
+ for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
+ // Check the pattern.
+ let ty_span = try { inputs_hir?.get(idx)?.span };
+ fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
+
+ // Check that argument is Sized.
+ // 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 {
+ fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
+ }
+
+ fcx.write_ty(param.hir_id, param_ty);
+ }
+
+ inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
+
+ fcx.in_tail_expr = true;
+ if let ty::Dynamic(..) = declared_ret_ty.kind() {
+ // FIXME: We need to verify that the return type is `Sized` after the return expression has
+ // been evaluated so that we have types available for all the nodes being returned, but that
+ // 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.in_tail_expr = false;
+
+ // We insert the deferred_generator_interiors entry after visiting the body.
+ // This ensures that all nested generators appear before the entry of this generator.
+ // resolve_generator_interiors relies on this property.
+ let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
+ let interior = fcx
+ .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
+ fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
+
+ let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
+ Some(GeneratorTypes {
+ resume_ty,
+ yield_ty,
+ interior,
+ movability: can_be_generator.unwrap(),
+ })
+ } else {
+ None
+ };
+
+ // Finalize the return check by taking the LUB of the return types
+ // we saw and assigning it to the expected return type. This isn't
+ // really expected to fail, since the coercions would have failed
+ // earlier when trying to find a LUB.
+ let coercion = fcx.ret_coercion.take().unwrap().into_inner();
+ let mut actual_return_ty = coercion.complete(&fcx);
+ debug!("actual_return_ty = {:?}", actual_return_ty);
+ if let ty::Dynamic(..) = declared_ret_ty.kind() {
+ // We have special-cased the case where the function is declared
+ // `-> dyn Foo` and we don't actually relate it to the
+ // `fcx.ret_coercion`, so just substitute a type variable.
+ actual_return_ty =
+ fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
+ debug!("actual_return_ty replaced with {:?}", actual_return_ty);
+ }
+
+ // HACK(oli-obk, compiler-errors): We should be comparing this against
+ // `declared_ret_ty`, but then anything uninferred would be inferred to
+ // the opaque type itself. That again would cause writeback to assume
+ // we have a recursive call site and do the sadly stabilized fallback to `()`.
+ fcx.demand_suptype(span, ret_ty, actual_return_ty);
+
+ // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
+ if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
+ && panic_impl_did == hir.local_def_id(fn_id).to_def_id()
+ {
+ check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
+ }
+
+ // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
+ if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
+ && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
+ {
+ check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
+ }
+
+ (fcx, gen_ty)
+}
+
+fn check_panic_info_fn(
+ tcx: TyCtxt<'_>,
+ fn_id: LocalDefId,
+ fn_sig: ty::FnSig<'_>,
+ decl: &hir::FnDecl<'_>,
+ declared_ret_ty: Ty<'_>,
+) {
+ let Some(panic_info_did) = tcx.lang_items().panic_info() else {
+ tcx.sess.err("language item required, but not found: `panic_info`");
+ return;
+ };
+
+ if *declared_ret_ty.kind() != ty::Never {
+ tcx.sess.span_err(decl.output.span(), "return type should be `!`");
+ }
+
+ let inputs = fn_sig.inputs();
+ if inputs.len() != 1 {
+ tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
+ return;
+ }
+
+ let arg_is_panic_info = match *inputs[0].kind() {
+ ty::Ref(region, ty, mutbl) => match *ty.kind() {
+ ty::Adt(ref adt, _) => {
+ adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
+ }
+ _ => false,
+ },
+ _ => false,
+ };
+
+ if !arg_is_panic_info {
+ tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
+ }
+
+ let DefKind::Fn = tcx.def_kind(fn_id) else {
+ let span = tcx.def_span(fn_id);
+ tcx.sess.span_err(span, "should be a function");
+ return;
+ };
+
+ let generic_counts = tcx.generics_of(fn_id).own_counts();
+ if generic_counts.types != 0 {
+ let span = tcx.def_span(fn_id);
+ tcx.sess.span_err(span, "should have no type parameters");
+ }
+ if generic_counts.consts != 0 {
+ let span = tcx.def_span(fn_id);
+ tcx.sess.span_err(span, "should have no const parameters");
+ }
+}
+
+fn check_alloc_error_fn(
+ tcx: TyCtxt<'_>,
+ fn_id: LocalDefId,
+ fn_sig: ty::FnSig<'_>,
+ decl: &hir::FnDecl<'_>,
+ declared_ret_ty: Ty<'_>,
+) {
+ let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
+ tcx.sess.err("language item required, but not found: `alloc_layout`");
+ return;
+ };
+
+ if *declared_ret_ty.kind() != ty::Never {
+ tcx.sess.span_err(decl.output.span(), "return type should be `!`");
+ }
+
+ let inputs = fn_sig.inputs();
+ if inputs.len() != 1 {
+ tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
+ return;
+ }
+
+ let arg_is_alloc_layout = match inputs[0].kind() {
+ ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
+ _ => false,
+ };
+
+ if !arg_is_alloc_layout {
+ tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
+ }
+
+ let DefKind::Fn = tcx.def_kind(fn_id) else {
+ let span = tcx.def_span(fn_id);
+ tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
+ return;
+ };
+
+ let generic_counts = tcx.generics_of(fn_id).own_counts();
+ if generic_counts.types != 0 {
+ let span = tcx.def_span(fn_id);
+ tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
+ }
+ if generic_counts.consts != 0 {
+ let span = tcx.def_span(fn_id);
+ tcx.sess
+ .span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
+ }
+}
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 9b943b160..a5a45f75e 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -2,12 +2,11 @@
use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
-use crate::astconv::AstConv;
-use crate::rustc_middle::ty::subst::Subst;
use hir::def::DefKind;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
+use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::infer::{InferOk, InferResult};
@@ -177,24 +176,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match *expected_ty.kind() {
ty::Opaque(def_id, substs) => {
let bounds = self.tcx.bound_explicit_item_bounds(def_id);
- let sig = bounds
- .transpose_iter()
- .map(|e| e.map_bound(|e| *e).transpose_tuple2())
- .find_map(|(pred, span)| match pred.0.kind().skip_binder() {
+ let sig =
+ bounds.subst_iter_copied(self.tcx, substs).find_map(|(pred, span)| match pred
+ .kind()
+ .skip_binder()
+ {
ty::PredicateKind::Projection(proj_predicate) => self
.deduce_sig_from_projection(
- Some(span.0),
- pred.0
- .kind()
- .rebind(pred.rebind(proj_predicate).subst(self.tcx, substs)),
+ Some(span),
+ pred.kind().rebind(proj_predicate),
),
_ => None,
});
let kind = bounds
- .transpose_iter()
- .map(|e| e.map_bound(|e| *e).transpose_tuple2())
- .filter_map(|(pred, _)| match pred.0.kind().skip_binder() {
+ .0
+ .iter()
+ .filter_map(|(pred, _)| match pred.kind().skip_binder() {
ty::PredicateKind::Trait(tp) => {
self.tcx.fn_trait_kind_from_lang_item(tp.def_id())
}
@@ -642,6 +640,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
),
bound_vars,
);
+ // Astconv can't normalize inputs or outputs with escaping bound vars,
+ // so normalize them here, after we've wrapped them in a binder.
+ let result = self.normalize_associated_types_in(self.tcx.hir().span(hir_id), result);
let c_result = self.inh.infcx.canonicalize_response(result);
self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
@@ -695,18 +696,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::Opaque(def_id, substs) => self
.tcx
.bound_explicit_item_bounds(def_id)
- .transpose_iter()
- .map(|e| e.map_bound(|e| *e).transpose_tuple2())
- .find_map(|(p, s)| get_future_output(p.subst(self.tcx, substs), s.0))?,
+ .subst_iter_copied(self.tcx, substs)
+ .find_map(|(p, s)| get_future_output(p, s))?,
ty::Error(_) => return None,
ty::Projection(proj)
if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
{
self.tcx
.bound_explicit_item_bounds(proj.item_def_id)
- .transpose_iter()
- .map(|e| e.map_bound(|e| *e).transpose_tuple2())
- .find_map(|(p, s)| get_future_output(p.subst(self.tcx, proj.substs), s.0))?
+ .subst_iter_copied(self.tcx, proj.substs)
+ .find_map(|(p, s)| get_future_output(p, s))?
}
_ => span_bug!(
self.tcx.def_span(expr_def_id),
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index def592c46..86597a703 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -35,8 +35,7 @@
//! // and are then unable to coerce `&7i32` to `&mut i32`.
//! ```
-use crate::astconv::AstConv;
-use crate::check::FnCtxt;
+use crate::FnCtxt;
use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
};
@@ -44,6 +43,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::Expr;
+use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{Coercion, InferOk, InferResult};
use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt};
@@ -61,7 +61,7 @@ use rustc_span::symbol::sym;
use rustc_span::{self, BytePos, DesugaringKind, Span};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
use smallvec::{smallvec, SmallVec};
@@ -216,6 +216,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
ty::Ref(r_b, _, mutbl_b) => {
return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b);
}
+ ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star => {
+ return self.coerce_dyn_star(a, b, predicates, region);
+ }
_ => {}
}
@@ -702,7 +705,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// Object safety violations or miscellaneous.
Err(err) => {
- self.report_selection_error(obligation.clone(), &obligation, &err, false);
+ self.err_ctxt().report_selection_error(
+ obligation.clone(),
+ &obligation,
+ &err,
+ false,
+ );
// Treat this like an obligation and follow through
// with the unsizing - the lack of a coercion should
// be silent, as it causes a type mismatch later.
@@ -740,6 +748,63 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
Ok(coercion)
}
+ fn coerce_dyn_star(
+ &self,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>,
+ predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+ b_region: ty::Region<'tcx>,
+ ) -> CoerceResult<'tcx> {
+ if !self.tcx.features().dyn_star {
+ return Err(TypeError::Mismatch);
+ }
+
+ if let ty::Dynamic(a_data, _, _) = a.kind()
+ && let ty::Dynamic(b_data, _, _) = b.kind()
+ {
+ if a_data.principal_def_id() == b_data.principal_def_id() {
+ return self.unify_and(a, b, |_| vec![]);
+ } else if !self.tcx().features().trait_upcasting {
+ let mut err = feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::trait_upcasting,
+ self.cause.span,
+ &format!(
+ "cannot cast `{a}` to `{b}`, trait upcasting coercion is experimental"
+ ),
+ );
+ err.emit();
+ }
+ }
+
+ // Check the obligations of the cast -- for example, when casting
+ // `usize` to `dyn* Clone + 'static`:
+ let obligations = predicates
+ .iter()
+ .map(|predicate| {
+ // For each existential predicate (e.g., `?Self: Clone`) substitute
+ // the type of the expression (e.g., `usize` in our example above)
+ // and then require that the resulting predicate (e.g., `usize: Clone`)
+ // holds (it does).
+ let predicate = predicate.with_self_ty(self.tcx, a);
+ Obligation::new(self.cause.clone(), self.param_env, predicate)
+ })
+ // Enforce the region bound (e.g., `usize: 'static`, in our example).
+ .chain([Obligation::new(
+ self.cause.clone(),
+ self.param_env,
+ self.tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
+ ty::OutlivesPredicate(a, b_region),
+ ))),
+ )])
+ .collect();
+
+ Ok(InferOk {
+ value: (vec![Adjustment { kind: Adjust::DynStar, target: b }], b),
+ obligations,
+ })
+ }
+
fn coerce_from_safe_fn<F, G>(
&self,
a: Ty<'tcx>,
@@ -1549,7 +1614,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
}
}
_ => {
- err = fcx.report_mismatched_types(
+ err = fcx.err_ctxt().report_mismatched_types(
cause,
expected,
found,
@@ -1629,7 +1694,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
expression: Option<&'tcx hir::Expr<'tcx>>,
blk_id: Option<hir::HirId>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
- let mut err = fcx.report_mismatched_types(cause, expected, found, ty_err);
+ let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err);
let mut pointing_at_return_type = false;
let mut fn_output = None;
@@ -1683,7 +1748,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
expected,
found,
can_suggest,
- fcx.tcx.hir().local_def_id_to_hir_id(fcx.tcx.hir().get_parent_item(id)),
+ fcx.tcx.hir().get_parent_item(id).into(),
);
}
if !pointing_at_return_type {
@@ -1692,7 +1757,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
}
let parent_id = fcx.tcx.hir().get_parent_item(id);
- let parent_item = fcx.tcx.hir().get_by_def_id(parent_id);
+ let parent_item = fcx.tcx.hir().get_by_def_id(parent_id.def_id);
if let (Some(expr), Some(_), Some((fn_decl, _, _))) =
(expression, blk_id, fcx.get_node_fn_decl(parent_item))
@@ -1704,7 +1769,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
expected,
found,
id,
- fcx.tcx.hir().local_def_id_to_hir_id(parent_id),
+ parent_id.into(),
);
}
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index e1d55ff82..16febfc46 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -1,21 +1,20 @@
-use crate::check::FnCtxt;
-use rustc_infer::infer::InferOk;
-use rustc_middle::middle::stability::EvalResult;
-use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::ObligationCause;
-
+use crate::FnCtxt;
use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{is_range_literal, Node};
+use rustc_infer::infer::InferOk;
use rustc_middle::lint::in_external_macro;
+use rustc_middle::middle::stability::EvalResult;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{BytePos, Span};
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::ObligationCause;
use super::method::probe;
@@ -32,17 +31,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
error: Option<TypeError<'tcx>>,
) {
self.annotate_expected_due_to_let_ty(err, expr, error);
- self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
- self.suggest_compatible_variants(err, expr, expected, expr_ty);
- self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty);
- if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
- return;
- }
- self.suggest_no_capture_closure(err, expected, expr_ty);
- self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
- self.suggest_missing_parentheses(err, expr);
- self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected);
- self.suggest_copied_or_cloned(err, expr, expr_ty, expected);
+
+ // Use `||` to give these suggestions a precedence
+ let _ = self.suggest_missing_parentheses(err, expr)
+ || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr)
+ || self.suggest_compatible_variants(err, expr, expected, expr_ty)
+ || 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_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
+ || self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
+ || self.suggest_into(err, expr, expr_ty, expected);
+
self.note_type_is_not_clone(err, expected, expr_ty, expr);
self.note_need_for_fn_pointer(err, expected, expr_ty);
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
@@ -77,7 +78,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.register_predicates(obligations);
None
}
- Err(e) => Some(self.report_mismatched_types(&cause, expected, actual, e)),
+ Err(e) => Some(self.err_ctxt().report_mismatched_types(&cause, expected, actual, e)),
}
}
@@ -107,7 +108,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.register_predicates(obligations);
None
}
- Err(e) => Some(self.report_mismatched_types(cause, expected, actual, e)),
+ Err(e) => Some(self.err_ctxt().report_mismatched_types(cause, expected, actual, e)),
}
}
@@ -151,7 +152,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let expr = expr.peel_drop_temps();
let cause = self.misc(expr.span);
let expr_ty = self.resolve_vars_with_obligations(checked_ty);
- let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e.clone());
+ let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e.clone());
let is_insufficiently_polymorphic =
matches!(e, TypeError::RegionsInsufficientlyPolymorphic(..));
@@ -286,7 +287,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
expected: Ty<'tcx>,
expr_ty: Ty<'tcx>,
- ) {
+ ) -> bool {
if let ty::Adt(expected_adt, substs) = expected.kind() {
if let hir::ExprKind::Field(base, ident) = expr.kind {
let base_ty = self.typeck_results.borrow().expr_ty(base);
@@ -299,7 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"",
Applicability::MaybeIncorrect,
);
- return
+ return true;
}
}
@@ -338,7 +339,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) {
vec!["None", "Some(())"]
} else {
- return;
+ return false;
};
if let Some(indent) =
self.tcx.sess.source_map().indentation_before(span.shrink_to_lo())
@@ -358,7 +359,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MaybeIncorrect,
);
}
- return;
+ return true;
}
}
}
@@ -375,7 +376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let field_is_local = sole_field.did.is_local();
let field_is_accessible =
- sole_field.vis.is_accessible_from(expr.hir_id.owner, self.tcx)
+ sole_field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx)
// Skip suggestions for unstable public fields (for example `Pin::pointer`)
&& matches!(self.tcx.eval_stability(sole_field.did, None, expr.span, None), EvalResult::Allow | EvalResult::Unmarked);
@@ -417,6 +418,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir::def::CtorKind::Const => unreachable!(),
};
+ // Suggest constructor as deep into the block tree as possible.
+ // This fixes https://github.com/rust-lang/rust/issues/101065,
+ // and also just helps make the most minimal suggestions.
+ let mut expr = expr;
+ while let hir::ExprKind::Block(block, _) = &expr.kind
+ && let Some(expr_) = &block.expr
+ {
+ expr = expr_
+ }
+
vec![
(expr.span.shrink_to_lo(), format!("{prefix}{variant}{open}")),
(expr.span.shrink_to_hi(), close.to_owned()),
@@ -435,6 +446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggestions_for(&**variant, *ctor_kind, *field_name),
Applicability::MaybeIncorrect,
);
+ return true;
}
_ => {
// More than one matching variant.
@@ -450,9 +462,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
),
Applicability::MaybeIncorrect,
);
+ return true;
}
}
}
+
+ false
}
fn suggest_non_zero_new_unwrap(
@@ -461,19 +476,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
expected: Ty<'tcx>,
expr_ty: Ty<'tcx>,
- ) {
+ ) -> bool {
let tcx = self.tcx;
let (adt, unwrap) = match expected.kind() {
// In case Option<NonZero*> is wanted, but * is provided, suggest calling new
ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
// Unwrap option
- let ty::Adt(adt, _) = substs.type_at(0).kind() else { return };
+ let ty::Adt(adt, _) = substs.type_at(0).kind() else { return false; };
(adt, "")
}
// In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types
ty::Adt(adt, _) => (adt, ".unwrap()"),
- _ => return,
+ _ => return false,
};
let map = [
@@ -492,7 +507,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some((s, _)) = map
.iter()
.find(|&&(s, t)| self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t))
- else { return };
+ else { return false; };
let path = self.tcx.def_path_str(adt.non_enum_variant().def_id);
@@ -504,6 +519,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
],
Applicability::MaybeIncorrect,
);
+
+ true
}
pub fn get_conversion_methods(
@@ -513,24 +530,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
checked_ty: Ty<'tcx>,
hir_id: hir::HirId,
) -> Vec<AssocItem> {
- let mut methods =
- self.probe_for_return_type(span, probe::Mode::MethodCall, expected, checked_ty, hir_id);
- methods.retain(|m| {
- self.has_only_self_parameter(m)
- && self
- .tcx
- // This special internal attribute is used to permit
- // "identity-like" conversion methods to be suggested here.
- //
- // FIXME (#46459 and #46460): ideally
- // `std::convert::Into::into` and `std::borrow:ToOwned` would
- // also be `#[rustc_conversion_suggestion]`, if not for
- // method-probing false-positives and -negatives (respectively).
- //
- // FIXME? Other potential candidate methods: `as_ref` and
- // `as_mut`?
- .has_attr(m.def_id, sym::rustc_conversion_suggestion)
- });
+ let methods = self.probe_for_return_type(
+ span,
+ probe::Mode::MethodCall,
+ expected,
+ checked_ty,
+ hir_id,
+ |m| {
+ self.has_only_self_parameter(m)
+ && self
+ .tcx
+ // This special internal attribute is used to permit
+ // "identity-like" conversion methods to be suggested here.
+ //
+ // FIXME (#46459 and #46460): ideally
+ // `std::convert::Into::into` and `std::borrow:ToOwned` would
+ // also be `#[rustc_conversion_suggestion]`, if not for
+ // method-probing false-positives and -negatives (respectively).
+ //
+ // FIXME? Other potential candidate methods: `as_ref` and
+ // `as_mut`?
+ .has_attr(m.def_id, sym::rustc_conversion_suggestion)
+ },
+ );
methods
}
@@ -697,7 +719,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
- ) -> Option<(Span, String, String, Applicability, bool /* verbose */)> {
+ ) -> Option<(
+ Span,
+ String,
+ String,
+ Applicability,
+ bool, /* verbose */
+ bool, /* suggest `&` or `&mut` type annotation */
+ )> {
let sess = self.sess();
let sp = expr.span;
@@ -729,6 +758,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
String::new(),
Applicability::MachineApplicable,
true,
+ false,
));
}
}
@@ -743,6 +773,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"b".to_string(),
Applicability::MachineApplicable,
true,
+ false,
));
}
}
@@ -800,6 +831,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
sugg.2,
Applicability::MachineApplicable,
false,
+ false,
));
}
@@ -827,6 +859,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("{prefix}&mut {sugg_expr}"),
Applicability::MachineApplicable,
false,
+ false,
),
hir::Mutability::Not => (
sp,
@@ -834,6 +867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("{prefix}&{sugg_expr}"),
Applicability::MachineApplicable,
false,
+ false,
),
});
}
@@ -863,6 +897,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
String::new(),
Applicability::MachineApplicable,
true,
+ true
));
}
return None;
@@ -876,6 +911,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
String::new(),
Applicability::MachineApplicable,
true,
+ true,
));
}
}
@@ -942,6 +978,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
src,
applicability,
true,
+ false,
));
}
}
@@ -982,6 +1019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MachineApplicable
},
true,
+ false,
));
}
@@ -1033,6 +1071,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggestion,
Applicability::MachineApplicable,
true,
+ false,
));
}
}
diff --git a/compiler/rustc_typeck/src/check/diverges.rs b/compiler/rustc_hir_typeck/src/diverges.rs
index 963a93a95..963a93a95 100644
--- a/compiler/rustc_typeck/src/check/diverges.rs
+++ b/compiler/rustc_hir_typeck/src/diverges.rs
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
new file mode 100644
index 000000000..175037f9b
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -0,0 +1,126 @@
+//! Errors emitted by `rustc_hir_analysis`.
+use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_middle::ty::Ty;
+use rustc_span::{symbol::Ident, Span};
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_field_multiply_specified_in_initializer, code = "E0062")]
+pub struct FieldMultiplySpecifiedInInitializer {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[label(previous_use_label)]
+ pub prev_span: Span,
+ pub ident: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_return_stmt_outside_of_fn_body, code = "E0572")]
+pub struct ReturnStmtOutsideOfFnBody {
+ #[primary_span]
+ pub span: Span,
+ #[label(encl_body_label)]
+ pub encl_body_span: Option<Span>,
+ #[label(encl_fn_label)]
+ pub encl_fn_span: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_yield_expr_outside_of_generator, code = "E0627")]
+pub struct YieldExprOutsideOfGenerator {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_struct_expr_non_exhaustive, code = "E0639")]
+pub struct StructExprNonExhaustive {
+ #[primary_span]
+ pub span: Span,
+ pub what: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_method_call_on_unknown_type, code = "E0699")]
+pub struct MethodCallOnUnknownType {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_functional_record_update_on_non_struct, code = "E0436")]
+pub struct FunctionalRecordUpdateOnNonStruct {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_address_of_temporary_taken, code = "E0745")]
+pub struct AddressOfTemporaryTaken {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+pub enum AddReturnTypeSuggestion {
+ #[suggestion(
+ hir_analysis_add_return_type_add,
+ code = "-> {found} ",
+ applicability = "machine-applicable"
+ )]
+ Add {
+ #[primary_span]
+ span: Span,
+ found: String,
+ },
+ #[suggestion(
+ hir_analysis_add_return_type_missing_here,
+ code = "-> _ ",
+ applicability = "has-placeholders"
+ )]
+ MissingHere {
+ #[primary_span]
+ span: Span,
+ },
+}
+
+#[derive(Subdiagnostic)]
+pub enum ExpectedReturnTypeLabel<'tcx> {
+ #[label(hir_analysis_expected_default_return_type)]
+ Unit {
+ #[primary_span]
+ span: Span,
+ },
+ #[label(hir_analysis_expected_return_type)]
+ Other {
+ #[primary_span]
+ span: Span,
+ expected: Ty<'tcx>,
+ },
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_missing_parentheses_in_range, code = "E0689")]
+pub struct MissingParentheseInRange {
+ #[primary_span]
+ #[label(hir_analysis_missing_parentheses_in_range)]
+ pub span: Span,
+ pub ty_str: String,
+ pub method_name: String,
+ #[subdiagnostic]
+ pub add_missing_parentheses: Option<AddMissingParenthesesInRange>,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion_verbose(
+ hir_analysis_add_missing_parentheses_in_range,
+ applicability = "maybe-incorrect"
+)]
+pub struct AddMissingParenthesesInRange {
+ pub func_name: String,
+ #[suggestion_part(code = "(")]
+ pub left: Span,
+ #[suggestion_part(code = ")")]
+ pub right: Span,
+}
diff --git a/compiler/rustc_typeck/src/check/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs
index e9e810344..e9e810344 100644
--- a/compiler/rustc_typeck/src/check/expectation.rs
+++ b/compiler/rustc_hir_typeck/src/expectation.rs
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 93b008500..9fde62a81 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -2,23 +2,22 @@
//!
//! See `mod.rs` for more context on type checking in general.
-use crate::astconv::AstConv as _;
-use crate::check::cast::{self, CastCheckResult};
-use crate::check::coercion::CoerceMany;
-use crate::check::fatally_break_rust;
-use crate::check::method::SelfSource;
-use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
-use crate::check::{
- report_unexpected_variant_res, BreakableCtxt, Diverges, DynamicCoerceMany, FnCtxt, Needs,
- TupleArgumentsFlag::DontTupleArguments,
-};
+use crate::cast;
+use crate::coercion::CoerceMany;
+use crate::coercion::DynamicCoerceMany;
+use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
use crate::errors::{
FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
YieldExprOutsideOfGenerator,
};
+use crate::fatally_break_rust;
+use crate::method::SelfSource;
use crate::type_error_struct;
-
-use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
+use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
+use crate::{
+ report_unexpected_variant_res, BreakableCtxt, Diverges, FnCtxt, Needs,
+ TupleArgumentsFlag::DontTupleArguments,
+};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -32,6 +31,8 @@ use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{Closure, ExprKind, HirId, QPath};
+use rustc_hir_analysis::astconv::AstConv as _;
+use rustc_hir_analysis::check::ty_kind_suggestion;
use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::InferOk;
@@ -41,6 +42,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
use rustc_middle::ty::error::TypeError::FieldMisMatch;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitable};
+use rustc_session::errors::ExprParenthesesNeeded;
use rustc_session::parse::feature_err;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::lev_distance::find_best_match_for_name;
@@ -394,7 +396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(sp) =
tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
{
- tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp);
+ err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
}
err.emit();
oprnd_t = tcx.ty_error();
@@ -541,7 +543,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// been resolved or we errored. This is important as we can only check transmute
// on concrete types, but the output type may not be known yet (it would only
// be known if explicitly specified via turbofish).
- self.deferred_transmute_checks.borrow_mut().push((from, to, expr.span));
+ self.deferred_transmute_checks.borrow_mut().push((from, to, expr.hir_id));
}
if !tcx.features().unsized_fn_params {
// We want to remove some Sized bounds from std functions,
@@ -752,7 +754,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
kind: hir::ImplItemKind::Fn(..),
span: encl_fn_span,
..
- })) = self.tcx.hir().find_by_def_id(encl_item_id)
+ })) = self.tcx.hir().find_by_def_id(encl_item_id.def_id)
{
// We are inside a function body, so reporting "return statement
// outside of function body" needs an explanation.
@@ -761,7 +763,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If this didn't hold, we would not have to report an error in
// the first place.
- assert_ne!(encl_item_id, encl_body_owner_id);
+ assert_ne!(encl_item_id.def_id, encl_body_owner_id);
let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id);
let encl_body = self.tcx.hir().body(encl_body_id);
@@ -881,7 +883,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
- // FIXME: Make this use SessionDiagnostic once error codes can be dynamically set.
+ // FIXME: Make this use Diagnostic once error codes can be dynamically set.
let mut err = self.tcx.sess.struct_span_err_with_code(
op_span,
"invalid left-hand side of assignment",
@@ -1044,6 +1046,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let rhs_ty = self.check_expr(&rhs);
let (applicability, eq) = if self.can_coerce(rhs_ty, lhs_ty) {
(Applicability::MachineApplicable, true)
+ } else if let ExprKind::Binary(
+ Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
+ _,
+ rhs_expr,
+ ) = lhs.kind
+ {
+ // if x == 1 && y == 2 { .. }
+ // +
+ let actual_lhs_ty = self.check_expr(&rhs_expr);
+ (Applicability::MaybeIncorrect, self.can_coerce(rhs_ty, actual_lhs_ty))
+ } else if let ExprKind::Binary(
+ Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
+ lhs_expr,
+ _,
+ ) = rhs.kind
+ {
+ // if x == 1 && y == 2 { .. }
+ // +
+ let actual_rhs_ty = self.check_expr(&lhs_expr);
+ (Applicability::MaybeIncorrect, self.can_coerce(actual_rhs_ty, lhs_ty))
} else {
(Applicability::MaybeIncorrect, false)
};
@@ -1066,9 +1088,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if eq {
err.span_suggestion_verbose(
- span,
+ span.shrink_to_hi(),
"you might have meant to compare for equality",
- "==",
+ '=',
applicability,
);
}
@@ -1109,11 +1131,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
- self.check_lhs_assignable(lhs, "E0070", span, |err| {
- let rhs_ty = self.check_expr(&rhs);
- suggest_deref_binop(err, rhs_ty);
- });
-
// This is (basically) inlined `check_expr_coercable_to_type`, but we want
// to suggest an additional fixup here in `suggest_deref_binop`.
let rhs_ty = self.check_expr_with_hint(&rhs, lhs_ty);
@@ -1124,6 +1141,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
diag.emit();
}
+ self.check_lhs_assignable(lhs, "E0070", span, |err| {
+ if let Some(rhs_ty) = self.typeck_results.borrow().expr_ty_opt(rhs) {
+ suggest_deref_binop(err, rhs_ty);
+ }
+ });
+
self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
if lhs_ty.references_error() || rhs_ty.references_error() {
@@ -1249,9 +1272,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
// Defer other checks until we're done type checking.
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
- match cast::check_cast(self, e, t_expr, t_cast, t.span, expr.span) {
- CastCheckResult::Ok => t_cast,
- CastCheckResult::Deferred(cast_check) => {
+ match cast::CastCheck::new(
+ self,
+ e,
+ t_expr,
+ t_cast,
+ t.span,
+ expr.span,
+ self.param_env.constness(),
+ ) {
+ Ok(cast_check) => {
debug!(
"check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
t_cast, t_expr, cast_check,
@@ -1259,7 +1289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
deferred_cast_checks.push(cast_check);
t_cast
}
- CastCheckResult::Err(ErrorGuaranteed { .. }) => self.tcx.ty_error(),
+ Err(_) => self.tcx.ty_error(),
}
}
}
@@ -1341,7 +1371,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Create a new function context.
let fcx = FnCtxt::new(self, self.param_env.with_const(), body.value.hir_id);
- crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body);
+ crate::GatherLocalsVisitor::new(&fcx).visit_body(body);
let ty = fcx.check_expr_with_expectation(&body.value, expected);
fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
@@ -1640,13 +1670,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Err(_) => {
// This should never happen, since we're just subtyping the
// remaining_fields, but it's fine to emit this, I guess.
- self.report_mismatched_types(
- &cause,
- target_ty,
- fru_ty,
- FieldMisMatch(variant.name, ident.name),
- )
- .emit();
+ self.err_ctxt()
+ .report_mismatched_types(
+ &cause,
+ target_ty,
+ fru_ty,
+ FieldMisMatch(variant.name, ident.name),
+ )
+ .emit();
}
}
}
@@ -1933,7 +1964,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.set_tainted_by_errors();
return;
}
- let mut err = self.type_error_struct_with_diag(
+ let mut err = self.err_ctxt().type_error_struct_with_diag(
field.ident.span,
|actual| match ty.kind() {
ty::Adt(adt, ..) if adt.is_enum() => struct_span_err!(
@@ -2338,7 +2369,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let ty::Adt(def, _) = output_ty.kind() && !def.is_enum() {
def.non_enum_variant().fields.iter().any(|field| {
field.ident(self.tcx) == ident
- && field.vis.is_accessible_from(expr.hir_id.owner, self.tcx)
+ && field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx)
})
} else if let ty::Tuple(tys) = output_ty.kind()
&& let Ok(idx) = ident.as_str().parse::<usize>()
@@ -2863,14 +2894,3 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
-
-pub(super) fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
- Some(match ty.kind() {
- ty::Bool => "true",
- ty::Char => "'a'",
- ty::Int(_) | ty::Uint(_) => "42",
- ty::Float(_) => "3.14159",
- ty::Error(_) | ty::Never => return None,
- _ => "value",
- })
-}
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index f483342b4..fce2a5888 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -89,15 +89,6 @@ enum ConsumeMode {
Move,
}
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum MutateMode {
- Init,
- /// Example: `x = y`
- JustWrite,
- /// Example: `x += y`
- WriteAndRead,
-}
-
/// The ExprUseVisitor type
///
/// This is the code that actually walks the tree.
@@ -134,7 +125,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
/// - `typeck_results` --- typeck results for the code being analyzed
pub fn new(
delegate: &'a mut (dyn Delegate<'tcx> + 'a),
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
body_owner: LocalDefId,
param_env: ty::ParamEnv<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
@@ -583,7 +574,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
for adjustment in adjustments {
debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
match adjustment.kind {
- adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => {
+ adjustment::Adjust::NeverToAny
+ | adjustment::Adjust::Pointer(_)
+ | adjustment::Adjust::DynStar => {
// Creating a closure/fn-pointer or unsizing consumes
// the input and stores it into the resulting rvalue.
self.delegate_consume(&place_with_id, place_with_id.hir_id);
diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 4059b3403..747ecb036 100644
--- a/compiler/rustc_typeck/src/check/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -1,4 +1,4 @@
-use crate::check::FnCtxt;
+use crate::FnCtxt;
use rustc_data_structures::{
fx::{FxHashMap, FxHashSet},
graph::WithSuccessors,
@@ -72,7 +72,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
//
// - Unconstrained ints are replaced with `i32`.
//
- // - Unconstrained floats are replaced with with `f64`.
+ // - Unconstrained floats are replaced with `f64`.
//
// - Non-numerics may get replaced with `()` or `!`, depending on
// how they were categorized by `calculate_diverging_fallback`
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index a40478db9..6a1cffe3e 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1,12 +1,7 @@
-use crate::astconv::{
- AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
- GenericArgCountResult, IsMethodCall, PathSeg,
-};
-use crate::check::callee::{self, DeferredCallResolution};
-use crate::check::method::{self, MethodCallee, SelfSource};
-use crate::check::rvalue_scopes;
-use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
-
+use crate::callee::{self, DeferredCallResolution};
+use crate::method::{self, MethodCallee, SelfSource};
+use crate::rvalue_scopes;
+use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
@@ -15,26 +10,28 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ExprKind, GenericArg, Node, QPath};
+use rustc_hir_analysis::astconv::{
+ AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
+ GenericArgCountResult, IsMethodCall, PathSeg,
+};
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
use rustc_infer::infer::{InferOk, InferResult};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::subst::{
- self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts,
-};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{
self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, ToPolyTraitRef,
ToPredicate, Ty, UserType,
};
+use rustc_middle::ty::{GenericArgKind, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts};
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{
self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt,
};
@@ -60,17 +57,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
- self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| {
- let msg = format!("unreachable {}", kind);
- lint.build(&msg)
- .span_label(span, &msg)
- .span_label(
+ let msg = format!("unreachable {}", kind);
+ self.tcx().struct_span_lint_hir(
+ lint::builtin::UNREACHABLE_CODE,
+ id,
+ span,
+ &msg,
+ |lint| {
+ lint.span_label(span, &msg).span_label(
orig_span,
custom_note
.unwrap_or("any code following this expression is unreachable"),
)
- .emit();
- })
+ },
+ )
}
}
}
@@ -90,14 +90,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
) -> Ty<'tcx> {
// No Infer()? Nothing needs doing.
- if !ty.has_infer_types_or_consts() {
+ if !ty.has_non_region_infer() {
debug!("no inference var, nothing needs doing");
return ty;
}
// If `ty` is a type variable, see whether we already know what it is.
ty = self.resolve_vars_if_possible(ty);
- if !ty.has_infer_types_or_consts() {
+ if !ty.has_non_region_infer() {
debug!(?ty);
return ty;
}
@@ -489,18 +489,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> {
match length {
&hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span),
- hir::ArrayLen::Body(anon_const) => self.to_const(anon_const),
+ hir::ArrayLen::Body(anon_const) => {
+ let const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
+ let span = self.tcx.hir().span(anon_const.hir_id);
+ let c = ty::Const::from_anon_const(self.tcx, const_def_id);
+ self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None));
+ self.normalize_associated_types_in(span, c)
+ }
}
}
- pub fn to_const(&self, ast_c: &hir::AnonConst) -> ty::Const<'tcx> {
- let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
- let span = self.tcx.hir().span(ast_c.hir_id);
- let c = ty::Const::from_anon_const(self.tcx, const_def_id);
- self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None));
- self.normalize_associated_types_in(span, c)
- }
-
pub fn const_arg_to_const(
&self,
ast_c: &hir::AnonConst,
@@ -559,7 +557,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Registers an obligation for checking later, during regionck, that `arg` is well-formed.
pub fn register_wf_obligation(
&self,
- arg: subst::GenericArg<'tcx>,
+ arg: ty::GenericArg<'tcx>,
span: Span,
code: traits::ObligationCauseCode<'tcx>,
) {
@@ -604,9 +602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut generators = self.deferred_generator_interiors.borrow_mut();
for (body_id, interior, kind) in generators.drain(..) {
self.select_obligations_where_possible(false, |_| {});
- crate::check::generator_interior::resolve_interior(
- self, def_id, body_id, interior, kind,
- );
+ crate::generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
}
}
@@ -616,7 +612,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !errors.is_empty() {
self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
- self.report_fulfillment_errors(&errors, self.inh.body_id, false);
+ self.err_ctxt().report_fulfillment_errors(&errors, self.inh.body_id, false);
}
}
@@ -630,7 +626,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !result.is_empty() {
mutate_fulfillment_errors(&mut result);
self.adjust_fulfillment_errors_for_expr_obligation(&mut result);
- self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred);
+ self.err_ctxt().report_fulfillment_errors(
+ &result,
+ self.inh.body_id,
+ fallback_has_occurred,
+ );
}
}
@@ -1271,7 +1271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&mut self,
param: &ty::GenericParamDef,
arg: &GenericArg<'_>,
- ) -> subst::GenericArg<'tcx> {
+ ) -> ty::GenericArg<'tcx> {
match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
<dyn AstConv<'_>>::ast_region_to_region(self.fcx, lt, Some(param)).into()
@@ -1295,10 +1295,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn inferred_kind(
&mut self,
- substs: Option<&[subst::GenericArg<'tcx>]>,
+ substs: Option<&[ty::GenericArg<'tcx>]>,
param: &ty::GenericParamDef,
infer_args: bool,
- ) -> subst::GenericArg<'tcx> {
+ ) -> ty::GenericArg<'tcx> {
let tcx = self.fcx.tcx();
match param.kind {
GenericParamDefKind::Lifetime => {
@@ -1410,7 +1410,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
})
}
- #[instrument(level = "debug", skip(self, code, span, def_id, substs))]
+ #[instrument(level = "debug", skip(self, code, span, substs))]
fn add_required_obligations_with_code(
&self,
span: Span,
@@ -1418,15 +1418,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
substs: SubstsRef<'tcx>,
code: impl Fn(usize, Span) -> ObligationCauseCode<'tcx>,
) {
+ let param_env = self.param_env;
+
+ let remap = match self.tcx.def_kind(def_id) {
+ // Associated consts have `Self: ~const Trait` bounds that should be satisfiable when
+ // `Self: Trait` is satisfied because it does not matter whether the impl is `const`.
+ // Therefore we have to remap the param env here to be non-const.
+ hir::def::DefKind::AssocConst => true,
+ hir::def::DefKind::AssocFn
+ if self.tcx.def_kind(self.tcx.parent(def_id)) == hir::def::DefKind::Trait =>
+ {
+ // N.B.: All callsites to this function involve checking a path expression.
+ //
+ // When instantiating a trait method as a function item, it does not actually matter whether
+ // the trait is `const` or not, or whether `where T: ~const Tr` needs to be satisfied as
+ // `const`. If we were to introduce instantiating trait methods as `const fn`s, we would
+ // check that after this, either via a bound `where F: ~const FnOnce` or when coercing to a
+ // `const fn` pointer.
+ //
+ // FIXME(fee1-dead) FIXME(const_trait_impl): update this doc when trait methods can satisfy
+ // `~const FnOnce` or can be coerced to `const fn` pointer.
+ true
+ }
+ _ => false,
+ };
let (bounds, _) = self.instantiate_bounds(span, def_id, &substs);
- for obligation in traits::predicates_for_generics(
+ for mut obligation in traits::predicates_for_generics(
|idx, predicate_span| {
traits::ObligationCause::new(span, self.body_id, code(idx, predicate_span))
},
- self.param_env,
+ param_env,
bounds,
) {
+ if remap {
+ obligation = obligation.without_const(self.tcx);
+ }
self.register_predicate(obligation);
}
}
@@ -1440,7 +1467,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty
} else {
if !self.is_tainted_by_errors() {
- self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true)
+ self.err_ctxt()
+ .emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true)
.emit();
}
let err = self.tcx.ty_error();
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
index fc83994ca..fc83994ca 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 311fcaada..8e0fcb56c 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1,19 +1,13 @@
-use crate::astconv::AstConv;
-use crate::check::coercion::CoerceMany;
-use crate::check::fn_ctxt::arg_matrix::{
- ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx,
+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::{
+ struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs,
+ TupleArgumentsFlag,
};
-use crate::check::gather_locals::Declaration;
-use crate::check::intrinsicck::InlineAsmCtxt;
-use crate::check::method::MethodCallee;
-use crate::check::Expectation::*;
-use crate::check::TupleArgumentsFlag::*;
-use crate::check::{
- potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt,
- LocalTy, Needs, TupleArgumentsFlag,
-};
-use crate::structured_errors::StructuredDiagnostic;
-
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan};
@@ -21,6 +15,10 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{ExprKind, Node, QPath};
+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_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -35,23 +33,34 @@ use rustc_span::{self, sym, Span};
use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
use std::iter;
+use std::mem;
use std::ops::ControlFlow;
use std::slice;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
- pub(in super::super) fn check_casts(&self) {
- let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
+ pub(in super::super) fn check_casts(&mut self) {
+ // don't hold the borrow to deferred_cast_checks while checking to avoid borrow checker errors
+ // when writing to `self.param_env`.
+ let mut deferred_cast_checks = mem::take(&mut *self.deferred_cast_checks.borrow_mut());
+
debug!("FnCtxt::check_casts: {} deferred checks", deferred_cast_checks.len());
for cast in deferred_cast_checks.drain(..) {
+ let prev_env = self.param_env;
+ self.param_env = self.param_env.with_constness(cast.constness);
+
cast.check(self);
+
+ self.param_env = prev_env;
}
+
+ *self.deferred_cast_checks.borrow_mut() = deferred_cast_checks;
}
pub(in super::super) fn check_transmutes(&self) {
let mut deferred_transmute_checks = self.deferred_transmute_checks.borrow_mut();
debug!("FnCtxt::check_transmutes: {} deferred checks", deferred_transmute_checks.len());
- for (from, to, span) in deferred_transmute_checks.drain(..) {
- self.check_transmute(span, from, to);
+ for (from, to, hir_id) in deferred_transmute_checks.drain(..) {
+ self.check_transmute(from, to, hir_id);
}
}
@@ -63,7 +72,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let get_operand_ty = |expr| {
let ty = self.typeck_results.borrow().expr_ty_adjusted(expr);
let ty = self.resolve_vars_if_possible(ty);
- if ty.has_infer_types_or_consts() {
+ if ty.has_non_region_infer() {
assert!(self.is_tainted_by_errors());
self.tcx.ty_error()
} else {
@@ -391,7 +400,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty: Ty<'tcx>,
cast_ty: &str,
) {
- use crate::structured_errors::MissingCastForVariadicArg;
+ use rustc_hir_analysis::structured_errors::MissingCastForVariadicArg;
MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit();
}
@@ -650,7 +659,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if tys.len() == 1 {
// A tuple wrap suggestion actually occurs within,
// so don't do anything special here.
- err = self.report_and_explain_type_error(
+ err = self.err_ctxt().report_and_explain_type_error(
TypeTrace::types(
&self.misc(*lo),
true,
@@ -742,7 +751,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let cause = &self.misc(provided_span);
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) {
- self.report_and_explain_type_error(trace, *e).emit();
+ self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
return true;
}
false
@@ -766,7 +775,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx];
let cause = &self.misc(provided_arg_span);
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
- let mut err = self.report_and_explain_type_error(trace, *err);
+ let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err);
self.emit_coerce_suggestions(
&mut err,
&provided_args[*provided_idx],
@@ -840,7 +849,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let cause = &self.misc(provided_span);
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
if let Some(e) = error {
- self.note_type_err(
+ self.err_ctxt().note_type_err(
&mut err,
&trace.cause,
None,
@@ -1199,7 +1208,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => bug!("unexpected type: {:?}", ty),
},
Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
- | Res::SelfTy { .. } => match ty.kind() {
+ | Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. } => match ty.kind() {
ty::Adt(adt, substs) if !adt.is_enum() => {
Some((adt.non_enum_variant(), adt.did(), substs))
}
@@ -1473,7 +1483,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&mut |err| {
if let Some(expected_ty) = expected.only_has_type(self) {
if !self.consider_removing_semicolon(blk, expected_ty, err) {
- self.consider_returning_binding(blk, expected_ty, err);
+ self.err_ctxt().consider_returning_binding(
+ blk,
+ expected_ty,
+ err,
+ );
}
if expected_ty == self.tcx.types.bool {
// If this is caused by a missing `let` in a `while let`,
@@ -1543,7 +1557,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
- let node = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(id));
+ let node = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(id).def_id);
match node {
Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })
| Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => {
@@ -1559,7 +1573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
- let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id));
+ let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id);
self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 0e22971d3..0c600daf4 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -6,13 +6,13 @@ mod suggestions;
pub use _impl::*;
pub use suggestions::*;
-use crate::astconv::AstConv;
-use crate::check::coercion::DynamicCoerceMany;
-use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
-
+use crate::coercion::DynamicCoerceMany;
+use crate::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
+use rustc_hir_analysis::astconv::AstConv;
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;
@@ -35,7 +35,7 @@ use std::ops::Deref;
///
/// See [`ItemCtxt`]'s docs for more.
///
-/// [`ItemCtxt`]: crate::collect::ItemCtxt
+/// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt
/// [`InferCtxt`]: infer::InferCtxt
pub struct FnCtxt<'a, 'tcx> {
pub(super) body_id: hir::HirId,
@@ -117,7 +117,7 @@ pub struct FnCtxt<'a, 'tcx> {
pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
- pub(super) inh: &'a Inherited<'a, 'tcx>,
+ pub(super) inh: &'a Inherited<'tcx>,
/// True if the function or closure's return type is known before
/// entering the function/closure, i.e. if the return type is
@@ -131,7 +131,7 @@ pub struct FnCtxt<'a, 'tcx> {
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn new(
- inh: &'a Inherited<'a, 'tcx>,
+ inh: &'a Inherited<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
) -> FnCtxt<'a, 'tcx> {
@@ -168,13 +168,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self.tcx.sess
}
+ /// Creates an `TypeErrCtxt` with a reference to the in-progress
+ /// `TypeckResults` which is used for diagnostics.
+ /// Use [`InferCtxt::err_ctxt`] to start one without a `TypeckResults`.
+ ///
+ /// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt
+ pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
+ TypeErrCtxt { infcx: &self.infcx, typeck_results: Some(self.typeck_results.borrow()) }
+ }
+
pub fn errors_reported_since_creation(&self) -> bool {
self.tcx.sess.err_count() > self.err_count_on_creation
}
}
impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
- type Target = Inherited<'a, 'tcx>;
+ type Target = Inherited<'tcx>;
fn deref(&self) -> &Self::Target {
&self.inh
}
@@ -276,7 +285,6 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
self,
- self.tcx,
span,
item_def_id,
item_segment,
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index ee0ad7b5d..4db9c56f9 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1,9 +1,7 @@
use super::FnCtxt;
-use crate::astconv::AstConv;
-use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
-use hir::def_id::DefId;
-use rustc_ast::util::parser::ExprPrecedence;
+use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
+use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind};
@@ -11,13 +9,16 @@ use rustc_hir::lang_items::LangItem;
use rustc_hir::{
Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
};
+use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::{self, TyCtxtInferExt};
use rustc_infer::traits::{self, StatementAsExpression};
use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty};
+use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty};
+use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::DefIdOrName;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -64,7 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
/// When encountering an fn-like type, try accessing the output of the type
- /// // and suggesting calling it if it satisfies a predicate (i.e. if the
+ /// and suggesting calling it if it satisfies a predicate (i.e. if the
/// output has a method or a field):
/// ```compile_fail,E0308
/// fn foo(x: usize) -> usize { x }
@@ -89,7 +90,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if ty.is_suggestable(self.tcx, false) {
format!("/* {ty} */")
} else {
- "".to_string()
+ "/* value */".to_string()
}
})
.collect::<Vec<_>>()
@@ -101,10 +102,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let msg = match def_id_or_name {
DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
- DefKind::Ctor(CtorOf::Struct, _) => "instantiate this tuple struct".to_string(),
- DefKind::Ctor(CtorOf::Variant, _) => {
- "instantiate this tuple variant".to_string()
- }
+ DefKind::Ctor(CtorOf::Struct, _) => "construct this tuple struct".to_string(),
+ DefKind::Ctor(CtorOf::Variant, _) => "construct this tuple variant".to_string(),
kind => format!("call this {}", kind.descr(def_id)),
},
DefIdOrName::Name(name) => format!("call this {name}"),
@@ -138,7 +137,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
sugg,
applicability,
);
-
return true;
}
false
@@ -327,9 +325,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
found: Ty<'tcx>,
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
- ) {
+ ) -> bool {
let expr = expr.peel_blocks();
- if let Some((sp, msg, suggestion, applicability, verbose)) =
+ if let Some((sp, msg, suggestion, applicability, verbose, annotation)) =
self.check_ref(expr, found, expected)
{
if verbose {
@@ -337,12 +335,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
err.span_suggestion(sp, &msg, suggestion, applicability);
}
+ if annotation {
+ let suggest_annotation = match expr.peel_drop_temps().kind {
+ hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, _) => "&",
+ hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, _) => "&mut ",
+ _ => return true,
+ };
+ let mut tuple_indexes = Vec::new();
+ let mut expr_id = expr.hir_id;
+ for (parent_id, node) in self.tcx.hir().parent_iter(expr.hir_id) {
+ match node {
+ Node::Expr(&Expr { kind: ExprKind::Tup(subs), .. }) => {
+ tuple_indexes.push(
+ subs.iter()
+ .enumerate()
+ .find(|(_, sub_expr)| sub_expr.hir_id == expr_id)
+ .unwrap()
+ .0,
+ );
+ expr_id = parent_id;
+ }
+ Node::Local(local) => {
+ if let Some(mut ty) = local.ty {
+ while let Some(index) = tuple_indexes.pop() {
+ match ty.kind {
+ TyKind::Tup(tys) => ty = &tys[index],
+ _ => return true,
+ }
+ }
+ let annotation_span = ty.span;
+ err.span_suggestion(
+ annotation_span.with_hi(annotation_span.lo()),
+ format!("alternatively, consider changing the type annotation"),
+ suggest_annotation,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ break;
+ }
+ _ => break,
+ }
+ }
+ }
+ return true;
+ } else if self.suggest_else_fn_with_closure(err, expr, found, expected) {
+ return true;
} else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
&& let ty::FnDef(def_id, ..) = &found.kind()
&& let Some(sp) = self.tcx.hir().span_if_local(*def_id)
{
err.span_label(sp, format!("{found} defined here"));
- } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
+ return true;
+ } else if self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
+ return true;
+ } else {
let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
if !methods.is_empty() {
let mut suggestions = methods.iter()
@@ -393,6 +439,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggestions,
Applicability::MaybeIncorrect,
);
+ return true;
}
} else if let ty::Adt(found_adt, found_substs) = found.kind()
&& self.tcx.is_diagnostic_item(sym::Option, found_adt.did())
@@ -417,9 +464,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!(".map(|x| &*{}x)", "*".repeat(ref_cnt)),
Applicability::MaybeIncorrect,
);
+ return true;
}
}
}
+
+ false
}
/// When encountering the expected boxed value allocated in the stack, suggest allocating it
@@ -430,13 +480,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
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;
+ return false;
}
if !expected.is_box() || found.is_box() {
- return;
+ return false;
}
let boxed_found = self.tcx.mk_box(found);
if self.can_coerce(boxed_found, expected) {
@@ -454,6 +504,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
https://doc.rust-lang.org/rust-by-example/std/box.html, and \
https://doc.rust-lang.org/std/boxed/index.html",
);
+ true
+ } else {
+ false
}
}
@@ -464,7 +517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err: &mut Diagnostic,
expected: Ty<'tcx>,
found: Ty<'tcx>,
- ) {
+ ) -> bool {
if let (ty::FnPtr(_), ty::Closure(def_id, _)) = (expected.kind(), found.kind()) {
if let Some(upvars) = self.tcx.upvars_mentioned(*def_id) {
// Report upto four upvars being captured to reduce the amount error messages
@@ -488,8 +541,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
multi_span,
"closures can only be coerced to `fn` types if they do not capture any variables"
);
+ return true;
}
}
+ false
}
/// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
@@ -860,18 +915,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
let ty = self.normalize_associated_types_in(expr.span, ty);
let ty = match self.tcx.asyncness(fn_id.owner) {
- hir::IsAsync::Async => self
- .tcx
- .infer_ctxt()
- .enter(|infcx| {
- infcx.get_impl_future_output_ty(ty).unwrap_or_else(|| {
+ hir::IsAsync::Async => {
+ let infcx = self.tcx.infer_ctxt().build();
+ infcx
+ .get_impl_future_output_ty(ty)
+ .unwrap_or_else(|| {
span_bug!(
fn_decl.output.span(),
"failed to get output type of async function"
)
})
- })
- .skip_binder(),
+ .skip_binder()
+ }
hir::IsAsync::NotAsync => ty,
};
if self.can_coerce(found, ty) {
@@ -891,11 +946,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
- ) {
+ ) -> bool {
let sp = self.tcx.sess.source_map().start_point(expr.span);
if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
// `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
- self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp);
+ err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
+ true
+ } else {
+ false
}
}
@@ -908,7 +966,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mut expr: &hir::Expr<'_>,
mut expr_ty: Ty<'tcx>,
mut expected_ty: Ty<'tcx>,
- ) {
+ ) -> bool {
loop {
match (&expr.kind, expr_ty.kind(), expected_ty.kind()) {
(
@@ -922,9 +980,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
(hir::ExprKind::Block(blk, _), _, _) => {
self.suggest_block_to_brackets(diag, *blk, expr_ty, expected_ty);
- break;
+ break true;
}
- _ => break,
+ _ => break false,
}
}
}
@@ -935,11 +993,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
expr_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>,
- ) {
- let ty::Adt(adt_def, substs) = expr_ty.kind() else { return; };
- let ty::Adt(expected_adt_def, expected_substs) = expected_ty.kind() else { return; };
+ ) -> bool {
+ let ty::Adt(adt_def, substs) = expr_ty.kind() else { return false; };
+ let ty::Adt(expected_adt_def, expected_substs) = expected_ty.kind() else { return false; };
if adt_def != expected_adt_def {
- return;
+ return false;
}
let mut suggest_copied_or_cloned = || {
@@ -958,6 +1016,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
".copied()",
Applicability::MachineApplicable,
);
+ return true;
} else if let Some(clone_did) = self.tcx.lang_items().clone_trait()
&& rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions(
self,
@@ -975,8 +1034,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
".cloned()",
Applicability::MachineApplicable,
);
+ return true;
}
}
+ false
};
if let Some(result_did) = self.tcx.get_diagnostic_item(sym::Result)
@@ -984,12 +1045,67 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Check that the error types are equal
&& self.can_eq(self.param_env, substs.type_at(1), expected_substs.type_at(1)).is_ok()
{
- suggest_copied_or_cloned();
+ return suggest_copied_or_cloned();
} else if let Some(option_did) = self.tcx.get_diagnostic_item(sym::Option)
&& adt_def.did() == option_did
{
- suggest_copied_or_cloned();
+ return suggest_copied_or_cloned();
}
+
+ false
+ }
+
+ pub(crate) fn suggest_into(
+ &self,
+ diag: &mut Diagnostic,
+ expr: &hir::Expr<'_>,
+ expr_ty: Ty<'tcx>,
+ expected_ty: Ty<'tcx>,
+ ) -> bool {
+ let expr = expr.peel_blocks();
+
+ // We have better suggestions for scalar interconversions...
+ if expr_ty.is_scalar() && expected_ty.is_scalar() {
+ return false;
+ }
+
+ // Don't suggest turning a block into another type (e.g. `{}.into()`)
+ if matches!(expr.kind, hir::ExprKind::Block(..)) {
+ return false;
+ }
+
+ // We'll later suggest `.as_ref` when noting the type error,
+ // so skip if we will suggest that instead.
+ if self.err_ctxt().should_suggest_as_ref(expected_ty, expr_ty).is_some() {
+ return false;
+ }
+
+ if let Some(into_def_id) = self.tcx.get_diagnostic_item(sym::Into)
+ && self.predicate_must_hold_modulo_regions(&traits::Obligation::new(
+ self.misc(expr.span),
+ self.param_env,
+ ty::Binder::dummy(ty::TraitRef {
+ def_id: into_def_id,
+ substs: self.tcx.mk_substs_trait(expr_ty, &[expected_ty.into()]),
+ })
+ .to_poly_trait_predicate()
+ .to_predicate(self.tcx),
+ ))
+ {
+ let sugg = if expr.precedence().order() >= PREC_POSTFIX {
+ vec![(expr.span.shrink_to_hi(), ".into()".to_owned())]
+ } else {
+ vec![(expr.span.shrink_to_lo(), "(".to_owned()), (expr.span.shrink_to_hi(), ").into()".to_owned())]
+ };
+ diag.multipart_suggestion(
+ format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),
+ sugg,
+ Applicability::MaybeIncorrect
+ );
+ return true;
+ }
+
+ false
}
/// Suggest wrapping the block in square brackets instead of curly braces
@@ -1110,7 +1226,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected_ty: Ty<'tcx>,
err: &mut Diagnostic,
) -> bool {
- if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) {
+ if let Some((span_semi, boxed)) = self.err_ctxt().could_remove_semicolon(blk, expected_ty) {
if let StatementAsExpression::NeedsBoxing = boxed {
err.span_suggestion_verbose(
span_semi,
@@ -1121,7 +1237,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
err.span_suggestion_short(
span_semi,
- "remove this semicolon",
+ "remove this semicolon to return this value",
"",
Applicability::MachineApplicable,
);
@@ -1132,8 +1248,3 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
-
-pub enum DefIdOrName {
- DefId(DefId),
- Name(&'static str),
-}
diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index 8f34a970f..9a096f24f 100644
--- a/compiler/rustc_typeck/src/check/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -1,9 +1,10 @@
-use crate::check::{FnCtxt, LocalTy, UserType};
+use crate::{FnCtxt, LocalTy};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::PatKind;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::Ty;
+use rustc_middle::ty::UserType;
use rustc_span::Span;
use rustc_trait_selection::traits;
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
index 016f4056b..122ad7009 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
@@ -210,7 +210,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
}
/// For an expression with an uninhabited return type (e.g. a function that returns !),
- /// this adds a self edge to to the CFG to model the fact that the function does not
+ /// this adds a self edge to the CFG to model the fact that the function does not
/// return.
fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
let ty = self.typeck_results.expr_ty(expr);
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs
index 139d17d2e..139d17d2e 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs
index c0a0bfe8e..c0a0bfe8e 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
index 518cd7342..4f3bdfbe7 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
@@ -14,7 +14,7 @@
use self::cfg_build::build_control_flow_graph;
use self::record_consumed_borrow::find_consumed_and_borrowed;
-use crate::check::FnCtxt;
+use crate::FnCtxt;
use hir::def_id::DefId;
use hir::{Body, HirId, HirIdMap, Node};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
index e22675e9d..bfe95852a 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -1,13 +1,16 @@
use super::TrackedValue;
use crate::{
- check::FnCtxt,
expr_use_visitor::{self, ExprUseVisitor},
+ FnCtxt,
};
use hir::{def_id::DefId, Body, HirId, HirIdMap};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
-use rustc_middle::hir::place::{PlaceBase, Projection, ProjectionKind};
use rustc_middle::ty::{ParamEnv, TyCtxt};
+use rustc_middle::{
+ hir::place::{PlaceBase, Projection, ProjectionKind},
+ ty::TypeVisitable,
+};
pub(super) fn find_consumed_and_borrowed<'a, 'tcx>(
fcx: &'a FnCtxt<'a, 'tcx>,
@@ -198,7 +201,13 @@ 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;`.
- if assignee_place.place.base_ty.needs_drop(self.tcx, self.param_env) {
+ let ty = self.tcx.erase_regions(assignee_place.place.base_ty);
+ if ty.needs_infer() {
+ self.tcx.sess.delay_span_bug(
+ self.tcx.hir().span(assignee_place.hir_id),
+ &format!("inference variables in {ty}"),
+ );
+ } else if ty.needs_drop(self.tcx, self.param_env) {
self.places
.borrowed
.insert(TrackedValue::from_place_with_projections_allowed(assignee_place));
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index 7ab6d9e2b..b7dd599cd 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -6,7 +6,7 @@
use self::drop_ranges::DropRanges;
use super::FnCtxt;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
-use rustc_errors::pluralize;
+use rustc_errors::{pluralize, DelayDm};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
@@ -218,7 +218,8 @@ pub fn resolve_interior<'a, 'tcx>(
.filter_map(|mut cause| {
// Erase regions and canonicalize late-bound regions to deduplicate as many types as we
// can.
- let erased = fcx.tcx.erase_regions(cause.ty);
+ let ty = fcx.normalize_associated_types_in(cause.span, cause.ty);
+ let erased = fcx.tcx.erase_regions(ty);
if captured_tys.insert(erased) {
// Replace all regions inside the generator interior with late bound regions.
// Note that each region slot in the types gets a new fresh late bound region,
@@ -263,7 +264,7 @@ pub fn resolve_interior<'a, 'tcx>(
// Unify the type variable inside the generator with the new witness
match fcx.at(&fcx.misc(body.value.span), fcx.param_env).eq(interior, witness) {
Ok(ok) => fcx.register_infer_ok_obligations(ok),
- _ => bug!(),
+ _ => bug!("failed to relate {interior} and {witness}"),
}
}
@@ -376,15 +377,6 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
debug!("is_borrowed_temporary: {:?}", self.drop_ranges.is_borrowed_temporary(expr));
let ty = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr);
- let may_need_drop = |ty: Ty<'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() {
- return true;
- }
- ty.needs_drop(self.fcx.tcx, self.fcx.param_env)
- };
// Typically, the value produced by an expression is consumed by its parent in some way,
// so we only have to check if the parent contains a yield (note that the parent may, for
@@ -402,9 +394,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
// src/test/ui/generator/drop-tracking-parent-expression.rs.
let scope = if self.drop_ranges.is_borrowed_temporary(expr)
|| ty.map_or(true, |ty| {
- let needs_drop = may_need_drop(ty);
- debug!(?needs_drop, ?ty);
- needs_drop
+ // 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() {
+ self.fcx
+ .tcx
+ .sess
+ .delay_span_bug(expr.span, &format!("inference variables in {ty}"));
+ true
+ } else {
+ ty.needs_drop(self.fcx.tcx, self.fcx.param_env)
+ }
}) {
self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
} else {
@@ -609,33 +610,33 @@ fn check_must_not_suspend_def(
rustc_session::lint::builtin::MUST_NOT_SUSPEND,
hir_id,
data.source_span,
- |lint| {
- let msg = format!(
+ DelayDm(|| {
+ format!(
"{}`{}`{} held across a suspend point, but should not be",
data.descr_pre,
tcx.def_path_str(def_id),
data.descr_post,
- );
- let mut err = lint.build(&msg);
-
+ )
+ }),
+ |lint| {
// add span pointing to the offending yield/await
- err.span_label(data.yield_span, "the value is held across this suspend point");
+ 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
- err.span_note(data.source_span, note.as_str());
+ 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?
- err.span_help(
+ lint.span_help(
data.source_span,
"consider using a block (`{ ... }`) \
to shrink the value's scope, ending before the suspend point",
);
- err.emit();
+ lint
},
);
diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs
index 37c830d4e..0fb7651b3 100644
--- a/compiler/rustc_typeck/src/check/inherited.rs
+++ b/compiler/rustc_hir_typeck/src/inherited.rs
@@ -6,7 +6,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::HirIdMap;
use rustc_infer::infer;
-use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
+use rustc_infer::infer::{DefiningAnchor, InferCtxt, InferOk, TyCtxtInferExt};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -29,10 +29,10 @@ use std::ops::Deref;
/// Here, the function `foo()` and the closure passed to
/// `bar()` will each have their own `FnCtxt`, but they will
/// share the inherited fields.
-pub struct Inherited<'a, 'tcx> {
- pub(super) infcx: InferCtxt<'a, 'tcx>,
+pub struct Inherited<'tcx> {
+ pub(super) infcx: InferCtxt<'tcx>,
- pub(super) typeck_results: &'a RefCell<ty::TypeckResults<'tcx>>,
+ pub(super) typeck_results: RefCell<ty::TypeckResults<'tcx>>,
pub(super) locals: RefCell<HirIdMap<super::LocalTy<'tcx>>>,
@@ -55,7 +55,7 @@ pub struct Inherited<'a, 'tcx> {
pub(super) deferred_cast_checks: RefCell<Vec<super::cast::CastCheck<'tcx>>>,
- pub(super) deferred_transmute_checks: RefCell<Vec<(Ty<'tcx>, Ty<'tcx>, Span)>>,
+ pub(super) deferred_transmute_checks: RefCell<Vec<(Ty<'tcx>, Ty<'tcx>, hir::HirId)>>,
pub(super) deferred_asm_checks: RefCell<Vec<(&'tcx hir::InlineAsm<'tcx>, hir::HirId)>>,
@@ -70,22 +70,23 @@ pub struct Inherited<'a, 'tcx> {
pub(super) diverging_type_vars: RefCell<FxHashSet<Ty<'tcx>>>,
}
-impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> {
- type Target = InferCtxt<'a, 'tcx>;
+impl<'tcx> Deref for Inherited<'tcx> {
+ type Target = InferCtxt<'tcx>;
fn deref(&self) -> &Self::Target {
&self.infcx
}
}
/// A temporary returned by `Inherited::build(...)`. This is necessary
-/// for multiple `InferCtxt` to share the same `in_progress_typeck_results`
+/// for multiple `InferCtxt` to share the same `typeck_results`
/// without using `Rc` or something similar.
pub struct InheritedBuilder<'tcx> {
infcx: infer::InferCtxtBuilder<'tcx>,
def_id: LocalDefId,
+ typeck_results: RefCell<ty::TypeckResults<'tcx>>,
}
-impl<'tcx> Inherited<'_, 'tcx> {
+impl<'tcx> Inherited<'tcx> {
pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> {
let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner;
@@ -93,7 +94,7 @@ impl<'tcx> Inherited<'_, 'tcx> {
infcx: tcx
.infer_ctxt()
.ignoring_regions()
- .with_fresh_in_progress_typeck_results(hir_owner)
+ .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id))
.with_normalize_fn_sig_for_diagnostic(Lrc::new(move |infcx, fn_sig| {
if fn_sig.has_escaping_bound_vars() {
return fn_sig;
@@ -117,26 +118,29 @@ impl<'tcx> Inherited<'_, 'tcx> {
})
})),
def_id,
+ typeck_results: RefCell::new(ty::TypeckResults::new(hir_owner)),
}
}
}
impl<'tcx> InheritedBuilder<'tcx> {
- pub fn enter<F, R>(&mut self, f: F) -> R
+ pub fn enter<F, R>(mut self, f: F) -> R
where
- F: for<'a> FnOnce(Inherited<'a, 'tcx>) -> R,
+ F: FnOnce(&Inherited<'tcx>) -> R,
{
let def_id = self.def_id;
- self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
+ f(&Inherited::new(self.infcx.build(), def_id, self.typeck_results))
}
}
-impl<'a, 'tcx> Inherited<'a, 'tcx> {
- fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
+impl<'tcx> Inherited<'tcx> {
+ fn new(
+ infcx: InferCtxt<'tcx>,
+ def_id: LocalDefId,
+ typeck_results: RefCell<ty::TypeckResults<'tcx>>,
+ ) -> Self {
let tcx = infcx.tcx;
let body_id = tcx.hir().maybe_body_owned_by(def_id);
- let typeck_results =
- infcx.in_progress_typeck_results.expect("building `FnCtxt` without typeck results");
Inherited {
typeck_results,
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
new file mode 100644
index 000000000..9812d96fc
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -0,0 +1,108 @@
+use hir::HirId;
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_index::vec::Idx;
+use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_target::abi::{Pointer, VariantIdx};
+
+use super::FnCtxt;
+
+/// If the type is `Option<T>`, it will return `T`, otherwise
+/// the type itself. Works on most `Option`-like types.
+fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+ let ty::Adt(def, substs) = *ty.kind() else { return ty };
+
+ if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() {
+ let data_idx;
+
+ let one = VariantIdx::new(1);
+ let zero = VariantIdx::new(0);
+
+ if def.variant(zero).fields.is_empty() {
+ data_idx = one;
+ } else if def.variant(one).fields.is_empty() {
+ data_idx = zero;
+ } else {
+ return ty;
+ }
+
+ if def.variant(data_idx).fields.len() == 1 {
+ return def.variant(data_idx).fields[0].ty(tcx, substs);
+ }
+ }
+
+ ty
+}
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+ pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
+ let tcx = self.tcx;
+ let span = tcx.hir().span(hir_id);
+ let normalize = |ty| {
+ let ty = self.resolve_vars_if_possible(ty);
+ self.tcx.normalize_erasing_regions(self.param_env, ty)
+ };
+ let from = normalize(from);
+ let to = normalize(to);
+ trace!(?from, ?to);
+
+ // Transmutes that are only changing lifetimes are always ok.
+ if from == to {
+ return;
+ }
+
+ let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env);
+ let sk_from = skel(from);
+ let sk_to = skel(to);
+ trace!(?sk_from, ?sk_to);
+
+ // Check for same size using the skeletons.
+ if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
+ if sk_from.same_size(sk_to) {
+ return;
+ }
+
+ // Special-case transmuting from `typeof(function)` and
+ // `Option<typeof(function)>` to present a clearer error.
+ let from = unpack_option_like(tcx, from);
+ if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.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}"))
+ .help("cast with `as` to a pointer instead")
+ .emit();
+ return;
+ }
+ }
+
+ // Try to display a sensible error with as much information as possible.
+ let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
+ Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()),
+ Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
+ Err(LayoutError::Unknown(bad)) => {
+ if bad == ty {
+ "this type does not have a fixed size".to_owned()
+ } else {
+ format!("size can vary because of {bad}")
+ }
+ }
+ Err(err) => err.to_string(),
+ };
+
+ let mut err = struct_span_err!(
+ tcx.sess,
+ span,
+ E0512,
+ "cannot transmute between types of different sizes, \
+ or dependently-sized types"
+ );
+ if from == to {
+ 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.emit();
+ }
+}
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
new file mode 100644
index 000000000..959c54866
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -0,0 +1,507 @@
+#![feature(if_let_guard)]
+#![feature(let_chains)]
+#![feature(try_blocks)]
+#![feature(never_type)]
+#![feature(min_specialization)]
+#![feature(control_flow_enum)]
+#![feature(drain_filter)]
+#![allow(rustc::potential_query_instability)]
+#![recursion_limit = "256"]
+
+#[macro_use]
+extern crate tracing;
+
+#[macro_use]
+extern crate rustc_middle;
+
+mod _match;
+mod autoderef;
+mod callee;
+// Used by clippy;
+pub mod cast;
+mod check;
+mod closure;
+mod coercion;
+mod demand;
+mod diverges;
+mod errors;
+mod expectation;
+mod expr;
+// Used by clippy;
+pub mod expr_use_visitor;
+mod fallback;
+mod fn_ctxt;
+mod gather_locals;
+mod generator_interior;
+mod inherited;
+mod intrinsicck;
+mod mem_categorization;
+mod method;
+mod op;
+mod pat;
+mod place_op;
+mod rvalue_scopes;
+mod upvar;
+mod writeback;
+
+pub use diverges::Diverges;
+pub use expectation::Expectation;
+pub use fn_ctxt::*;
+pub use inherited::{Inherited, InheritedBuilder};
+
+use crate::check::check_fn;
+use crate::coercion::DynamicCoerceMany;
+use crate::gather_locals::GatherLocalsVisitor;
+use rustc_data_structures::unord::UnordSet;
+use rustc_errors::{struct_span_err, MultiSpan};
+use rustc_hir as hir;
+use rustc_hir::def::Res;
+use rustc_hir::intravisit::Visitor;
+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_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::Span;
+
+#[macro_export]
+macro_rules! type_error_struct {
+ ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
+ let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
+
+ if $typ.references_error() {
+ err.downgrade_to_delayed_bug();
+ }
+
+ err
+ })
+}
+
+/// The type of a local binding, including the revealed type for anon types.
+#[derive(Copy, Clone, Debug)]
+pub struct LocalTy<'tcx> {
+ decl_ty: Ty<'tcx>,
+ revealed_ty: Ty<'tcx>,
+}
+
+#[derive(Copy, Clone)]
+pub struct UnsafetyState {
+ pub def: hir::HirId,
+ pub unsafety: hir::Unsafety,
+ from_fn: bool,
+}
+
+impl UnsafetyState {
+ pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
+ UnsafetyState { def, unsafety, from_fn: true }
+ }
+
+ pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
+ use hir::BlockCheckMode;
+ match self.unsafety {
+ // If this unsafe, then if the outer function was already marked as
+ // unsafe we shouldn't attribute the unsafe'ness to the block. This
+ // way the block can be warned about instead of ignoring this
+ // extraneous block (functions are never warned about).
+ hir::Unsafety::Unsafe if self.from_fn => self,
+
+ unsafety => {
+ let (unsafety, def) = match blk.rules {
+ BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
+ BlockCheckMode::DefaultBlock => (unsafety, self.def),
+ };
+ UnsafetyState { def, unsafety, from_fn: false }
+ }
+ }
+ }
+}
+
+/// If this `DefId` is a "primary tables entry", returns
+/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
+///
+/// If this function returns `Some`, then `typeck_results(def_id)` will
+/// succeed; if it returns `None`, then `typeck_results(def_id)` may or
+/// may not succeed. In some cases where this function returns `None`
+/// (notably closures), `typeck_results(def_id)` would wind up
+/// redirecting to the owning function.
+fn primary_body_of(
+ tcx: TyCtxt<'_>,
+ id: hir::HirId,
+) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
+ match tcx.hir().get(id) {
+ Node::Item(item) => match item.kind {
+ hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
+ Some((body, Some(ty), None))
+ }
+ hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
+ _ => None,
+ },
+ Node::TraitItem(item) => match item.kind {
+ hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
+ hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
+ Some((body, None, Some(sig)))
+ }
+ _ => None,
+ },
+ Node::ImplItem(item) => match item.kind {
+ hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
+ hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
+ _ => None,
+ },
+ Node::AnonConst(constant) => Some((constant.body, None, None)),
+ _ => None,
+ }
+}
+
+fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+ // Closures' typeck results come from their outermost function,
+ // as they are part of the same "inference environment".
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ if typeck_root_def_id != def_id {
+ return tcx.has_typeck_results(typeck_root_def_id);
+ }
+
+ if let Some(def_id) = def_id.as_local() {
+ let id = tcx.hir().local_def_id_to_hir_id(def_id);
+ primary_body_of(tcx, id).is_some()
+ } else {
+ false
+ }
+}
+
+fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDefId> {
+ &*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);
+ 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());
+ typeck_with_fallback(tcx, def_id, fallback)
+ }
+}
+
+/// Used only to get `TypeckResults` for type inference during error recovery.
+/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
+fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
+ let fallback = move || {
+ let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
+ tcx.ty_error_with_message(span, "diagnostic only typeck table used")
+ };
+ typeck_with_fallback(tcx, def_id, fallback)
+}
+
+fn typeck_with_fallback<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: LocalDefId,
+ fallback: impl Fn() -> Ty<'tcx> + 'tcx,
+) -> &'tcx ty::TypeckResults<'tcx> {
+ // Closures' typeck results come from their outermost function,
+ // as they are part of the same "inference environment".
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
+ if typeck_root_def_id != def_id {
+ return tcx.typeck(typeck_root_def_id);
+ }
+
+ let id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let span = tcx.hir().span(id);
+
+ // Figure out what primary body this item has.
+ let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
+ span_bug!(span, "can't type-check body of {:?}", def_id);
+ });
+ let body = tcx.hir().body(body_id);
+
+ let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
+ let param_env = tcx.param_env(def_id);
+ let mut fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
+ let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
+ let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
+ <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
+ } else {
+ tcx.fn_sig(def_id)
+ };
+
+ check_abi(tcx, id, span, fn_sig.abi());
+
+ // Compute the function signature from point of view of inside the fn.
+ let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
+ let fn_sig = inh.normalize_associated_types_in(
+ body.value.span,
+ body_id.hir_id,
+ param_env,
+ fn_sig,
+ );
+ check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
+ } else {
+ let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
+ let expected_type = body_ty
+ .and_then(|ty| match ty.kind {
+ hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
+ _ => None,
+ })
+ .unwrap_or_else(|| match tcx.hir().get(id) {
+ Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
+ Node::Expr(&hir::Expr {
+ kind: hir::ExprKind::ConstBlock(ref anon_const),
+ ..
+ }) if anon_const.hir_id == id => 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 => fcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::TypeInference,
+ span,
+ }),
+ Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
+ | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
+ let operand_ty = asm
+ .operands
+ .iter()
+ .filter_map(|(op, _op_sp)| match op {
+ hir::InlineAsmOperand::Const { anon_const }
+ if anon_const.hir_id == id =>
+ {
+ // Inline assembly constants must be integers.
+ Some(fcx.next_int_var())
+ }
+ hir::InlineAsmOperand::SymFn { anon_const }
+ if anon_const.hir_id == id =>
+ {
+ Some(fcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::MiscVariable,
+ span,
+ }))
+ }
+ _ => None,
+ })
+ .next();
+ operand_ty.unwrap_or_else(fallback)
+ }
+ _ => fallback(),
+ },
+ _ => fallback(),
+ });
+
+ let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
+ fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
+
+ // Gather locals in statics (because of block expressions).
+ GatherLocalsVisitor::new(&fcx).visit_body(body);
+
+ fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
+
+ fcx.write_ty(id, expected_type);
+
+ fcx
+ };
+
+ let fallback_has_occurred = fcx.type_inference_fallback();
+
+ // Even though coercion casts provide type hints, we check casts after fallback for
+ // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
+ fcx.check_casts();
+ fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
+
+ // Closure and generator analysis may run after fallback
+ // because they don't constrain other type variables.
+ // Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now)
+ let prev_constness = fcx.param_env.constness();
+ fcx.param_env = fcx.param_env.without_const();
+ fcx.closure_analyze(body);
+ fcx.param_env = fcx.param_env.with_constness(prev_constness);
+ assert!(fcx.deferred_call_resolutions.borrow().is_empty());
+ // Before the generator analysis, temporary scopes shall be marked to provide more
+ // precise information on types to be captured.
+ fcx.resolve_rvalue_scopes(def_id.to_def_id());
+ fcx.resolve_generator_interiors(def_id.to_def_id());
+
+ for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
+ let ty = fcx.normalize_ty(span, ty);
+ fcx.require_type_is_sized(ty, span, code);
+ }
+
+ fcx.select_all_obligations_or_error();
+
+ if !fcx.infcx.is_tainted_by_errors() {
+ fcx.check_transmutes();
+ }
+
+ fcx.check_asms();
+
+ fcx.infcx.skip_region_resolution();
+
+ fcx.resolve_type_vars_in_body(body)
+ });
+
+ // Consistency check our TypeckResults instance can hold all ItemLocalIds
+ // it will need to hold.
+ assert_eq!(typeck_results.hir_owner, id.owner);
+
+ typeck_results
+}
+
+/// When `check_fn` is invoked on a generator (i.e., a body that
+/// includes yield), it returns back some information about the yield
+/// points.
+struct GeneratorTypes<'tcx> {
+ /// Type of generator argument / values returned by `yield`.
+ resume_ty: Ty<'tcx>,
+
+ /// Type of value that is yielded.
+ yield_ty: Ty<'tcx>,
+
+ /// Types that are captured (see `GeneratorInterior` for more).
+ interior: Ty<'tcx>,
+
+ /// Indicates if the generator is movable or static (immovable).
+ movability: hir::Movability,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum Needs {
+ MutPlace,
+ None,
+}
+
+impl Needs {
+ fn maybe_mut_place(m: hir::Mutability) -> Self {
+ match m {
+ hir::Mutability::Mut => Needs::MutPlace,
+ hir::Mutability::Not => Needs::None,
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum PlaceOp {
+ Deref,
+ Index,
+}
+
+pub struct BreakableCtxt<'tcx> {
+ may_break: bool,
+
+ // this is `null` for loops where break with a value is illegal,
+ // such as `while`, `for`, and `while let`
+ coerce: Option<DynamicCoerceMany<'tcx>>,
+}
+
+pub struct EnclosingBreakables<'tcx> {
+ stack: Vec<BreakableCtxt<'tcx>>,
+ by_id: HirIdMap<usize>,
+}
+
+impl<'tcx> EnclosingBreakables<'tcx> {
+ fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
+ self.opt_find_breakable(target_id).unwrap_or_else(|| {
+ bug!("could not find enclosing breakable with id {}", target_id);
+ })
+ }
+
+ fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
+ match self.by_id.get(&target_id) {
+ Some(ix) => Some(&mut self.stack[*ix]),
+ None => None,
+ }
+ }
+}
+
+fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0533,
+ "expected unit struct, unit variant or constant, found {} `{}`",
+ res.descr(),
+ rustc_hir_pretty::qpath_to_string(qpath),
+ )
+ .emit();
+}
+
+/// Controls whether the arguments are tupled. This is used for the call
+/// operator.
+///
+/// Tupling means that all call-side arguments are packed into a tuple and
+/// passed as a single parameter. For example, if tupling is enabled, this
+/// function:
+/// ```
+/// fn f(x: (isize, isize)) {}
+/// ```
+/// Can be called as:
+/// ```ignore UNSOLVED (can this be done in user code?)
+/// # fn f(x: (isize, isize)) {}
+/// f(1, 2);
+/// ```
+/// Instead of:
+/// ```
+/// # fn f(x: (isize, isize)) {}
+/// f((1, 2));
+/// ```
+#[derive(Clone, Eq, PartialEq)]
+enum TupleArgumentsFlag {
+ DontTupleArguments,
+ TupleArguments,
+}
+
+fn fatally_break_rust(sess: &Session) {
+ let handler = sess.diagnostic();
+ handler.span_bug_no_panic(
+ MultiSpan::new(),
+ "It looks like you're trying to break rust; would you like some ICE?",
+ );
+ handler.note_without_error("the compiler expectedly panicked. this is a feature.");
+ handler.note_without_error(
+ "we would appreciate a joke overview: \
+ https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
+ );
+ handler.note_without_error(&format!(
+ "rustc {} running on {}",
+ option_env!("CFG_VERSION").unwrap_or("unknown_version"),
+ config::host_triple(),
+ ));
+}
+
+fn has_expected_num_generic_args<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ 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 }
+ })
+}
+
+pub fn provide(providers: &mut Providers) {
+ method::provide(providers);
+ *providers = Providers {
+ typeck_item_bodies,
+ typeck_const_arg,
+ typeck,
+ diagnostic_only_typeck,
+ has_typeck_results,
+ used_trait_imports,
+ ..*providers
+ };
+}
diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index ced919f66..362f1c343 100644
--- a/compiler/rustc_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -92,7 +92,7 @@ impl HirNode for hir::Pat<'_> {
#[derive(Clone)]
pub(crate) struct MemCategorizationContext<'a, 'tcx> {
pub(crate) typeck_results: &'a ty::TypeckResults<'tcx>,
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_owner: LocalDefId,
upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
@@ -103,7 +103,7 @@ pub(crate) type McResult<T> = Result<T, ()>;
impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
/// Creates a `MemCategorizationContext`.
pub(crate) fn new(
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_owner: LocalDefId,
typeck_results: &'a ty::TypeckResults<'tcx>,
@@ -184,7 +184,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
/// modes #42640) may look like `Some(x)` but in fact have
/// implicit deref patterns attached (e.g., it is really
/// `&Some(x)`). In that case, we return the "outermost" type
- /// (e.g., `&Option<T>).
+ /// (e.g., `&Option<T>`).
pub(crate) fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
// Check for implicit `&` types wrapping the pattern; note
// that these are never attached to binding patterns, so
@@ -265,6 +265,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
}
+ #[instrument(level = "debug", skip(self, previous))]
fn cat_expr_adjusted_with<F>(
&self,
expr: &hir::Expr<'_>,
@@ -274,7 +275,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
where
F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>,
{
- debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr);
let target = self.resolve_vars_if_possible(adjustment.target);
match adjustment.kind {
adjustment::Adjust::Deref(overloaded) => {
@@ -292,13 +292,15 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
adjustment::Adjust::NeverToAny
| adjustment::Adjust::Pointer(_)
- | adjustment::Adjust::Borrow(_) => {
+ | adjustment::Adjust::Borrow(_)
+ | adjustment::Adjust::DynStar => {
// Result is an rvalue.
Ok(self.cat_rvalue(expr.hir_id, expr.span, target))
}
}
}
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn cat_expr_unadjusted(
&self,
expr: &hir::Expr<'_>,
@@ -387,6 +389,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
}
+ #[instrument(level = "debug", skip(self, span))]
pub(crate) fn cat_res(
&self,
hir_id: hir::HirId,
@@ -394,8 +397,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
expr_ty: Ty<'tcx>,
res: Res,
) -> McResult<PlaceWithHirId<'tcx>> {
- debug!("cat_res: id={:?} expr={:?} def={:?}", hir_id, expr_ty, res);
-
match res {
Res::Def(
DefKind::Ctor(..)
@@ -475,13 +476,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
ret
}
+ #[instrument(level = "debug", skip(self))]
fn cat_overloaded_place(
&self,
expr: &hir::Expr<'_>,
base: &hir::Expr<'_>,
) -> McResult<PlaceWithHirId<'tcx>> {
- debug!("cat_overloaded_place(expr={:?}, base={:?})", expr, base);
-
// Reconstruct the output assuming it's a reference with the
// same region and mutability as the receiver. This holds for
// `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
@@ -497,13 +497,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
self.cat_deref(expr, base)
}
+ #[instrument(level = "debug", skip(self, node))]
fn cat_deref(
&self,
node: &impl HirNode,
base_place: PlaceWithHirId<'tcx>,
) -> McResult<PlaceWithHirId<'tcx>> {
- debug!("cat_deref: base_place={:?}", base_place);
-
let base_curr_ty = base_place.place.ty();
let deref_ty = match base_curr_ty.builtin_deref(true) {
Some(mt) => mt.ty,
@@ -562,7 +561,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
| Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
| Res::SelfCtor(..)
- | Res::SelfTy { .. } => {
+ | Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. } => {
// Structs and Unions have only have one variant.
Ok(VariantIdx::new(0))
}
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 59fd5c315..be4ea9986 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -1,16 +1,16 @@
use super::{probe, MethodCallee};
-use crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
-use crate::check::{callee, FnCtxt};
+use crate::{callee, FnCtxt};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::GenericArg;
+use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
use rustc_infer::infer::{self, InferOk};
use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::subst::{self, Subst, SubstsRef};
+use rustc_middle::ty::subst::{self, SubstsRef};
use rustc_middle::ty::{self, GenericParamDefKind, Ty};
use rustc_span::Span;
use rustc_trait_selection::traits;
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 249e9c66b..a1278edef 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -10,15 +10,14 @@ mod suggest;
pub use self::suggest::SelfSource;
pub use self::MethodError::*;
-use crate::check::{Expectation, FnCtxt};
-use crate::ObligationCause;
+use crate::{Expectation, FnCtxt};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diagnostic};
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::ty::subst::Subst;
+use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable};
use rustc_span::symbol::Ident;
diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
index 392695cca..3c98a2aa3 100644
--- a/compiler/rustc_typeck/src/check/method/prelude2021.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
@@ -1,3 +1,7 @@
+use crate::{
+ method::probe::{self, Pick},
+ FnCtxt,
+};
use hir::def_id::DefId;
use hir::HirId;
use hir::ItemKind;
@@ -12,11 +16,6 @@ use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
-use crate::check::{
- method::probe::{self, Pick},
- FnCtxt,
-};
-
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(super) fn lint_dot_call_from_2018(
&self,
@@ -82,14 +81,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
prelude_or_array_lint,
self_expr.hir_id,
self_expr.span,
+ format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
|lint| {
let sp = self_expr.span;
- let mut lint = lint.build(&format!(
- "trait method `{}` will become ambiguous in Rust 2021",
- segment.ident.name
- ));
-
let derefs = "*".repeat(pick.autoderefs);
let autoref = match pick.autoref_or_ptr_adjustment {
@@ -133,7 +128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
- lint.emit();
+ lint
},
);
} else {
@@ -143,6 +138,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
prelude_or_array_lint,
call_expr.hir_id,
call_expr.span,
+ format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
|lint| {
let sp = call_expr.span;
let trait_name = self.trait_path_or_bare_name(
@@ -151,11 +147,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pick.item.container_id(self.tcx),
);
- let mut lint = lint.build(&format!(
- "trait method `{}` will become ambiguous in Rust 2021",
- segment.ident.name
- ));
-
let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp);
if precise {
let args = args
@@ -202,7 +193,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
- lint.emit();
+ lint
},
);
}
@@ -257,15 +248,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
- self.tcx.struct_span_lint_hir(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| {
- // "type" refers to either a type or, more likely, a trait from which
- // the associated function or method is from.
- let container_id = pick.item.container_id(self.tcx);
- let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id);
- let trait_generics = self.tcx.generics_of(container_id);
-
- let trait_name =
- if trait_generics.params.len() <= trait_generics.has_self as usize {
+ self.tcx.struct_span_lint_hir(
+ RUST_2021_PRELUDE_COLLISIONS,
+ expr_id,
+ span,
+ format!(
+ "trait-associated function `{}` will become ambiguous in Rust 2021",
+ method_name.name
+ ),
+ |lint| {
+ // "type" refers to either a type or, more likely, a trait from which
+ // the associated function or method is from.
+ let container_id = pick.item.container_id(self.tcx);
+ let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id);
+ let trait_generics = self.tcx.generics_of(container_id);
+
+ let trait_name = if trait_generics.params.len() <= trait_generics.has_self as usize
+ {
trait_path
} else {
let counts = trait_generics.own_counts();
@@ -282,44 +281,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
};
- let mut lint = lint.build(&format!(
- "trait-associated function `{}` will become ambiguous in Rust 2021",
- method_name.name
- ));
-
- let mut self_ty_name = self_ty_span
- .find_ancestor_inside(span)
- .and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
- .unwrap_or_else(|| self_ty.to_string());
-
- // Get the number of generics the self type has (if an Adt) unless we can determine that
- // the user has written the self type with generics already which we (naively) do by looking
- // for a "<" in `self_ty_name`.
- if !self_ty_name.contains('<') {
- if let Adt(def, _) = self_ty.kind() {
- let generics = self.tcx.generics_of(def.did());
- if !generics.params.is_empty() {
- let counts = generics.own_counts();
- self_ty_name += &format!(
- "<{}>",
- std::iter::repeat("'_")
- .take(counts.lifetimes)
- .chain(std::iter::repeat("_").take(counts.types + counts.consts))
- .collect::<Vec<_>>()
- .join(", ")
- );
+ let mut self_ty_name = self_ty_span
+ .find_ancestor_inside(span)
+ .and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
+ .unwrap_or_else(|| self_ty.to_string());
+
+ // Get the number of generics the self type has (if an Adt) unless we can determine that
+ // the user has written the self type with generics already which we (naively) do by looking
+ // for a "<" in `self_ty_name`.
+ if !self_ty_name.contains('<') {
+ if let Adt(def, _) = self_ty.kind() {
+ let generics = self.tcx.generics_of(def.did());
+ if !generics.params.is_empty() {
+ let counts = generics.own_counts();
+ self_ty_name += &format!(
+ "<{}>",
+ std::iter::repeat("'_")
+ .take(counts.lifetimes)
+ .chain(
+ std::iter::repeat("_").take(counts.types + counts.consts)
+ )
+ .collect::<Vec<_>>()
+ .join(", ")
+ );
+ }
}
}
- }
- lint.span_suggestion(
- span,
- "disambiguate the associated function",
- format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,),
- Applicability::MachineApplicable,
- );
-
- lint.emit();
- });
+ lint.span_suggestion(
+ span,
+ "disambiguate the associated function",
+ format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,),
+ Applicability::MachineApplicable,
+ );
+
+ lint
+ },
+ );
}
fn trait_path_or_bare_name(
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index e9f55ab34..28aa2302f 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -3,14 +3,12 @@ use super::CandidateSource;
use super::MethodError;
use super::NoMatchData;
-use crate::check::FnCtxt;
use crate::errors::MethodCallOnUnknownType;
-use crate::hir::def::DefKind;
-use crate::hir::def_id::DefId;
-
+use crate::FnCtxt;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def::Namespace;
use rustc_infer::infer::canonical::OriginalQueryValues;
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
@@ -19,10 +17,11 @@ use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::middle::stability;
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
-use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_session::lint;
+use rustc_span::def_id::DefId;
use rustc_span::def_id::LocalDefId;
use rustc_span::lev_distance::{
find_best_match_for_name_with_substrings, lev_distance_with_substrings,
@@ -253,7 +252,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// would result in an error (basically, the same criteria we
/// would use to decide if a method is a plausible fit for
/// ambiguity purposes).
- #[instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self, candidate_filter))]
pub fn probe_for_return_type(
&self,
span: Span,
@@ -261,6 +260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return_type: Ty<'tcx>,
self_ty: Ty<'tcx>,
scope_expr_id: hir::HirId,
+ candidate_filter: impl Fn(&ty::AssocItem) -> bool,
) -> Vec<ty::AssocItem> {
let method_names = self
.probe_op(
@@ -272,7 +272,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self_ty,
scope_expr_id,
ProbeScope::AllTraits,
- |probe_cx| Ok(probe_cx.candidate_method_names()),
+ |probe_cx| Ok(probe_cx.candidate_method_names(candidate_filter)),
)
.unwrap_or_default();
method_names
@@ -409,9 +409,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lint::builtin::TYVAR_BEHIND_RAW_POINTER,
scope_expr_id,
span,
- |lint| {
- lint.build("type annotations needed").emit();
- },
+ "type annotations needed",
+ |lint| lint,
);
}
} else {
@@ -473,69 +472,65 @@ fn method_autoderef_steps<'tcx>(
) -> MethodAutoderefStepsResult<'tcx> {
debug!("method_autoderef_steps({:?})", goal);
- tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| {
- let ParamEnvAnd { param_env, value: self_ty } = goal;
-
- let mut autoderef =
- Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP)
- .include_raw_pointers()
- .silence_errors();
- let mut reached_raw_pointer = false;
- let mut steps: Vec<_> = autoderef
- .by_ref()
- .map(|(ty, d)| {
- let step = CandidateStep {
- self_ty: infcx.make_query_response_ignoring_pending_obligations(
- inference_vars.clone(),
- ty,
- ),
- autoderefs: d,
- from_unsafe_deref: reached_raw_pointer,
- unsize: false,
- };
- if let ty::RawPtr(_) = ty.kind() {
- // all the subsequent steps will be from_unsafe_deref
- reached_raw_pointer = true;
- }
- step
- })
- .collect();
-
- let final_ty = autoderef.final_ty(true);
- let opt_bad_ty = match final_ty.kind() {
- ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
- reached_raw_pointer,
- ty: infcx
- .make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
- }),
- ty::Array(elem_ty, _) => {
- let dereferences = steps.len() - 1;
-
- steps.push(CandidateStep {
- self_ty: infcx.make_query_response_ignoring_pending_obligations(
- inference_vars,
- infcx.tcx.mk_slice(*elem_ty),
- ),
- autoderefs: dereferences,
- // this could be from an unsafe deref if we had
- // a *mut/const [T; N]
- from_unsafe_deref: reached_raw_pointer,
- unsize: true,
- });
-
- None
+ let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal);
+ let ParamEnvAnd { param_env, value: self_ty } = goal;
+
+ let mut autoderef =
+ Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP)
+ .include_raw_pointers()
+ .silence_errors();
+ let mut reached_raw_pointer = false;
+ let mut steps: Vec<_> = autoderef
+ .by_ref()
+ .map(|(ty, d)| {
+ let step = CandidateStep {
+ self_ty: infcx
+ .make_query_response_ignoring_pending_obligations(inference_vars.clone(), ty),
+ autoderefs: d,
+ from_unsafe_deref: reached_raw_pointer,
+ unsize: false,
+ };
+ if let ty::RawPtr(_) = ty.kind() {
+ // all the subsequent steps will be from_unsafe_deref
+ reached_raw_pointer = true;
}
- _ => None,
- };
-
- debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
+ step
+ })
+ .collect();
+
+ let final_ty = autoderef.final_ty(true);
+ let opt_bad_ty = match final_ty.kind() {
+ ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
+ reached_raw_pointer,
+ ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
+ }),
+ ty::Array(elem_ty, _) => {
+ let dereferences = steps.len() - 1;
+
+ steps.push(CandidateStep {
+ self_ty: infcx.make_query_response_ignoring_pending_obligations(
+ inference_vars,
+ infcx.tcx.mk_slice(*elem_ty),
+ ),
+ autoderefs: dereferences,
+ // this could be from an unsafe deref if we had
+ // a *mut/const [T; N]
+ from_unsafe_deref: reached_raw_pointer,
+ unsize: true,
+ });
- MethodAutoderefStepsResult {
- steps: tcx.arena.alloc_from_iter(steps),
- opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)),
- reached_recursion_limit: autoderef.reached_recursion_limit(),
+ None
}
- })
+ _ => None,
+ };
+
+ debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
+
+ MethodAutoderefStepsResult {
+ steps: tcx.arena.alloc_from_iter(steps),
+ opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)),
+ reached_recursion_limit: autoderef.reached_recursion_limit(),
+ }
}
impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
@@ -972,12 +967,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
- fn candidate_method_names(&self) -> Vec<Ident> {
+ fn candidate_method_names(
+ &self,
+ candidate_filter: impl Fn(&ty::AssocItem) -> bool,
+ ) -> Vec<Ident> {
let mut set = FxHashSet::default();
let mut names: Vec<_> = self
.inherent_candidates
.iter()
.chain(&self.extension_candidates)
+ .filter(|candidate| candidate_filter(&candidate.item))
.filter(|candidate| {
if let Some(return_ty) = self.return_type {
self.matches_return_type(&candidate.item, None, return_ty)
@@ -1358,24 +1357,24 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
stable_pick: &Pick<'_>,
unstable_candidates: &[(Candidate<'tcx>, Symbol)],
) {
+ let def_kind = stable_pick.item.kind.as_def_kind();
self.tcx.struct_span_lint_hir(
lint::builtin::UNSTABLE_NAME_COLLISIONS,
self.scope_expr_id,
self.span,
+ format!(
+ "{} {} with this name may be added to the standard library in the future",
+ def_kind.article(),
+ def_kind.descr(stable_pick.item.def_id),
+ ),
|lint| {
- let def_kind = stable_pick.item.kind.as_def_kind();
- let mut diag = lint.build(&format!(
- "{} {} with this name may be added to the standard library in the future",
- def_kind.article(),
- def_kind.descr(stable_pick.item.def_id),
- ));
match (stable_pick.item.kind, stable_pick.item.container) {
(ty::AssocKind::Fn, _) => {
// FIXME: This should be a `span_suggestion` instead of `help`
// However `self.span` only
// highlights the method name, so we can't use it. Also consider reusing
// the code from `report_method_error()`.
- diag.help(&format!(
+ lint.help(&format!(
"call with fully qualified syntax `{}(...)` to keep using the current \
method",
self.tcx.def_path_str(stable_pick.item.def_id),
@@ -1383,7 +1382,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
(ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer) => {
let def_id = stable_pick.item.container_id(self.tcx);
- diag.span_suggestion(
+ lint.span_suggestion(
self.span,
"use the fully qualified path to the associated const",
format!(
@@ -1399,7 +1398,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
if self.tcx.sess.is_nightly_build() {
for (candidate, feature) in unstable_candidates {
- diag.help(&format!(
+ lint.help(&format!(
"add `#![feature({})]` to the crate attributes to enable `{}`",
feature,
self.tcx.def_path_str(candidate.item.def_id),
@@ -1407,7 +1406,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
- diag.emit();
+ lint
},
);
}
@@ -1695,7 +1694,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
pcx.allow_similar_names = true;
pcx.assemble_inherent_candidates();
- let method_names = pcx.candidate_method_names();
+ let method_names = pcx.candidate_method_names(|_| true);
pcx.allow_similar_names = false;
let applicable_close_candidates: Vec<ty::AssocItem> = method_names
.iter()
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 2d459b2cc..6c21ed902 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1,7 +1,9 @@
//! Give useful errors and suggestions to users when an item can't be
//! found or is otherwise invalid.
-use crate::check::FnCtxt;
+use crate::errors;
+use crate::FnCtxt;
+use rustc_ast::ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
@@ -21,7 +23,7 @@ use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span};
-use rustc_trait_selection::traits::error_reporting::on_unimplemented::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{
FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedNote,
@@ -30,7 +32,7 @@ use rustc_trait_selection::traits::{
use std::cmp::Ordering;
use std::iter;
-use super::probe::{IsSuggestion, Mode, ProbeScope};
+use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
use super::{CandidateSource, MethodError, NoMatchData};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -104,7 +106,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let report_candidates = |span: Span,
err: &mut Diagnostic,
- mut sources: Vec<CandidateSource>,
+ sources: &mut Vec<CandidateSource>,
sugg_span: Span| {
sources.sort();
sources.dedup();
@@ -246,7 +248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match error {
MethodError::NoMatch(NoMatchData {
- static_candidates: static_sources,
+ static_candidates: mut static_sources,
unsatisfied_predicates,
out_of_scope_traits,
lev_candidate,
@@ -270,7 +272,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
- if self.suggest_constraining_numerical_ty(
+ if self.suggest_wrapping_range_with_parens(
+ tcx, actual, source, span, item_name, &ty_str,
+ ) || self.suggest_constraining_numerical_ty(
tcx, actual, source, span, item_kind, item_name, &ty_str,
) {
return None;
@@ -418,9 +422,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.help(&format!("try with `{}::{}`", ty_str, item_name,));
}
- report_candidates(span, &mut err, static_sources, sugg_span);
+ report_candidates(span, &mut err, &mut static_sources, sugg_span);
} else if static_sources.len() > 1 {
- report_candidates(span, &mut err, static_sources, sugg_span);
+ report_candidates(span, &mut err, &mut static_sources, sugg_span);
}
let mut bound_spans = vec![];
@@ -854,8 +858,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Avoid crashing.
return (None, None);
}
- let OnUnimplementedNote { message, label, .. } =
- self.on_unimplemented_note(trait_ref, &obligation);
+ let OnUnimplementedNote { message, label, .. } = self
+ .err_ctxt()
+ .on_unimplemented_note(trait_ref, &obligation);
(message, label)
})
.unwrap_or((None, None))
@@ -983,7 +988,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_for_field_method(&mut err, source, span, actual, item_name);
}
- self.check_for_unwrap_self(&mut err, source, span, actual, item_name);
+ self.check_for_inner_self(&mut err, source, span, actual, item_name);
bound_spans.sort();
bound_spans.dedup();
@@ -1002,6 +1007,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
source,
out_of_scope_traits,
&unsatisfied_predicates,
+ &static_sources,
unsatisfied_bounds,
);
}
@@ -1074,7 +1080,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return Some(err);
}
- MethodError::Ambiguity(sources) => {
+ MethodError::Ambiguity(mut sources) => {
let mut err = struct_span_err!(
self.sess(),
item_name.span,
@@ -1083,7 +1089,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
err.span_label(item_name.span, format!("multiple `{}` found", item_name));
- report_candidates(span, &mut err, sources, sugg_span);
+ report_candidates(span, &mut err, &mut sources, sugg_span);
err.emit();
}
@@ -1200,6 +1206,89 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false
}
+ /// Suggest possible range with adding parentheses, for example:
+ /// when encountering `0..1.map(|i| i + 1)` suggest `(0..1).map(|i| i + 1)`.
+ fn suggest_wrapping_range_with_parens(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ actual: Ty<'tcx>,
+ source: SelfSource<'tcx>,
+ span: Span,
+ item_name: Ident,
+ ty_str: &str,
+ ) -> bool {
+ if let SelfSource::MethodCall(expr) = source {
+ for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) {
+ if let Node::Expr(parent_expr) = parent {
+ let lang_item = match parent_expr.kind {
+ ExprKind::Struct(ref qpath, _, _) => match **qpath {
+ QPath::LangItem(LangItem::Range, ..) => Some(LangItem::Range),
+ QPath::LangItem(LangItem::RangeTo, ..) => Some(LangItem::RangeTo),
+ QPath::LangItem(LangItem::RangeToInclusive, ..) => {
+ Some(LangItem::RangeToInclusive)
+ }
+ _ => None,
+ },
+ ExprKind::Call(ref func, _) => match func.kind {
+ // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
+ ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)) => {
+ Some(LangItem::RangeInclusiveStruct)
+ }
+ _ => None,
+ },
+ _ => None,
+ };
+
+ if lang_item.is_none() {
+ continue;
+ }
+
+ let span_included = match parent_expr.kind {
+ hir::ExprKind::Struct(_, eps, _) => {
+ eps.len() > 0 && eps.last().map_or(false, |ep| ep.span.contains(span))
+ }
+ // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
+ hir::ExprKind::Call(ref func, ..) => func.span.contains(span),
+ _ => false,
+ };
+
+ if !span_included {
+ continue;
+ }
+
+ let range_def_id = self.tcx.require_lang_item(lang_item.unwrap(), None);
+ let range_ty =
+ self.tcx.bound_type_of(range_def_id).subst(self.tcx, &[actual.into()]);
+
+ let pick = self.probe_for_name(
+ span,
+ Mode::MethodCall,
+ item_name,
+ IsSuggestion(true),
+ range_ty,
+ expr.hir_id,
+ ProbeScope::AllTraits,
+ );
+ if pick.is_ok() {
+ let range_span = parent_expr.span.with_hi(expr.span.hi());
+ tcx.sess.emit_err(errors::MissingParentheseInRange {
+ span,
+ ty_str: ty_str.to_string(),
+ method_name: item_name.as_str().to_string(),
+ add_missing_parentheses: Some(errors::AddMissingParenthesesInRange {
+ func_name: item_name.name.as_str().to_string(),
+ left: range_span.shrink_to_lo(),
+ right: range_span.shrink_to_hi(),
+ }),
+ });
+ return true;
+ }
+ }
+ }
+ }
+ false
+ }
+
fn suggest_constraining_numerical_ty(
&self,
tcx: TyCtxt<'tcx>,
@@ -1262,7 +1351,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If this is a floating point literal that ends with '.',
// get rid of it to stop this from becoming a member access.
let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
-
err.span_suggestion(
lit.span,
&format!(
@@ -1395,7 +1483,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- fn check_for_unwrap_self(
+ fn check_for_inner_self(
&self,
err: &mut Diagnostic,
source: SelfSource<'tcx>,
@@ -1408,81 +1496,168 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id));
let ty::Adt(kind, substs) = actual.kind() else { return; };
- if !kind.is_enum() {
- return;
- }
+ match kind.adt_kind() {
+ ty::AdtKind::Enum => {
+ let matching_variants: Vec<_> = kind
+ .variants()
+ .iter()
+ .flat_map(|variant| {
+ let [field] = &variant.fields[..] else { return None; };
+ let field_ty = field.ty(tcx, substs);
+
+ // Skip `_`, since that'll just lead to ambiguity.
+ if self.resolve_vars_if_possible(field_ty).is_ty_var() {
+ return None;
+ }
- let matching_variants: Vec<_> = kind
- .variants()
- .iter()
- .flat_map(|variant| {
- let [field] = &variant.fields[..] else { return None; };
- let field_ty = field.ty(tcx, substs);
+ self.lookup_probe(
+ span,
+ item_name,
+ field_ty,
+ call_expr,
+ ProbeScope::TraitsInScope,
+ )
+ .ok()
+ .map(|pick| (variant, field, pick))
+ })
+ .collect();
+
+ let ret_ty_matches = |diagnostic_item| {
+ if let Some(ret_ty) = self
+ .ret_coercion
+ .as_ref()
+ .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
+ && let ty::Adt(kind, _) = ret_ty.kind()
+ && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
+ {
+ true
+ } else {
+ false
+ }
+ };
- // Skip `_`, since that'll just lead to ambiguity.
- if self.resolve_vars_if_possible(field_ty).is_ty_var() {
- return None;
+ match &matching_variants[..] {
+ [(_, field, pick)] => {
+ 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}`"),
+ );
+ let (article, kind, variant, question) =
+ if tcx.is_diagnostic_item(sym::Result, kind.did()) {
+ ("a", "Result", "Err", ret_ty_matches(sym::Result))
+ } else if tcx.is_diagnostic_item(sym::Option, kind.did()) {
+ ("an", "Option", "None", ret_ty_matches(sym::Option))
+ } else {
+ return;
+ };
+ if question {
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_hi(),
+ format!(
+ "use the `?` operator to extract the `{self_ty}` value, propagating \
+ {article} `{kind}::{variant}` value to the caller"
+ ),
+ "?",
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_hi(),
+ format!(
+ "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
+ panicking if the value is {article} `{kind}::{variant}`"
+ ),
+ ".expect(\"REASON\")",
+ Applicability::HasPlaceholders,
+ );
+ }
+ }
+ // FIXME(compiler-errors): Support suggestions for other matching enum variants
+ _ => {}
}
-
- self.lookup_probe(span, item_name, field_ty, call_expr, ProbeScope::AllTraits)
- .ok()
- .map(|pick| (variant, field, pick))
- })
- .collect();
-
- let ret_ty_matches = |diagnostic_item| {
- if let Some(ret_ty) = self
- .ret_coercion
- .as_ref()
- .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
- && let ty::Adt(kind, _) = ret_ty.kind()
- && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
- {
- true
- } else {
- false
}
- };
+ // Target wrapper types - types that wrap or pretend to wrap another type,
+ // perhaps this inner type is meant to be called?
+ ty::AdtKind::Struct | ty::AdtKind::Union => {
+ let [first] = ***substs else { return; };
+ let ty::GenericArgKind::Type(ty) = first.unpack() else { return; };
+ let Ok(pick) = self.lookup_probe(
+ span,
+ item_name,
+ ty,
+ call_expr,
+ ProbeScope::TraitsInScope,
+ ) else { return; };
- match &matching_variants[..] {
- [(_, field, pick)] => {
- 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}`"),
- );
- let (article, kind, variant, question) =
- if Some(kind.did()) == tcx.get_diagnostic_item(sym::Result) {
- ("a", "Result", "Err", ret_ty_matches(sym::Result))
- } else if Some(kind.did()) == tcx.get_diagnostic_item(sym::Option) {
- ("an", "Option", "None", ret_ty_matches(sym::Option))
- } else {
- return;
+ let name = self.ty_to_value_string(actual);
+ let inner_id = kind.did();
+ let mutable = if let Some(AutorefOrPtrAdjustment::Autoref { mutbl, .. }) =
+ pick.autoref_or_ptr_adjustment
+ {
+ Some(mutbl)
+ } else {
+ None
+ };
+
+ if tcx.is_diagnostic_item(sym::LocalKey, inner_id) {
+ err.help("use `with` or `try_with` to access thread local storage");
+ } else if Some(kind.did()) == tcx.lang_items().maybe_uninit() {
+ err.help(format!(
+ "if this `{name}` has been initialized, \
+ use one of the `assume_init` methods to access the inner value"
+ ));
+ } else if tcx.is_diagnostic_item(sym::RefCell, inner_id) {
+ let (suggestion, borrow_kind, panic_if) = match mutable {
+ Some(Mutability::Not) => (".borrow()", "borrow", "a mutable borrow exists"),
+ Some(Mutability::Mut) => {
+ (".borrow_mut()", "mutably borrow", "any borrows exist")
+ }
+ None => return,
};
- if question {
err.span_suggestion_verbose(
expr.span.shrink_to_hi(),
format!(
- "use the `?` operator to extract the `{self_ty}` value, propagating \
- {article} `{kind}::{variant}` value to the caller"
+ "use `{suggestion}` to {borrow_kind} the `{ty}`, \
+ panicking if {panic_if}"
),
- "?",
- Applicability::MachineApplicable,
+ suggestion,
+ Applicability::MaybeIncorrect,
);
- } else {
+ } else if tcx.is_diagnostic_item(sym::Mutex, inner_id) {
err.span_suggestion_verbose(
expr.span.shrink_to_hi(),
format!(
- "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
- panicking if the value is {article} `{kind}::{variant}`"
+ "use `.lock().unwrap()` to borrow the `{ty}`, \
+ blocking the current thread until it can be acquired"
),
- ".expect(\"REASON\")",
- Applicability::HasPlaceholders,
+ ".lock().unwrap()",
+ Applicability::MaybeIncorrect,
);
- }
+ } else if tcx.is_diagnostic_item(sym::RwLock, inner_id) {
+ let (suggestion, borrow_kind) = match mutable {
+ Some(Mutability::Not) => (".read().unwrap()", "borrow"),
+ Some(Mutability::Mut) => (".write().unwrap()", "mutably borrow"),
+ None => return,
+ };
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_hi(),
+ format!(
+ "use `{suggestion}` to {borrow_kind} the `{ty}`, \
+ blocking the current thread until it can be acquired"
+ ),
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ return;
+ };
+
+ err.span_note(
+ tcx.def_span(pick.item.def_id),
+ &format!("the method `{item_name}` exists on the type `{ty}`"),
+ );
}
- // FIXME(compiler-errors): Support suggestions for other matching enum variants
- _ => {}
}
}
@@ -1841,6 +2016,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Option<ty::Predicate<'tcx>>,
Option<ObligationCause<'tcx>>,
)],
+ static_candidates: &[CandidateSource],
unsatisfied_bounds: bool,
) {
let mut alt_rcvr_sugg = false;
@@ -1955,6 +2131,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None => true,
})
.filter(|info| {
+ // Static candidates are already implemented, and known not to work
+ // Do not suggest them again
+ static_candidates.iter().all(|sc| match *sc {
+ CandidateSource::Trait(def_id) => def_id != info.def_id,
+ CandidateSource::Impl(def_id) => {
+ self.tcx.trait_id_of_impl(def_id) != Some(info.def_id)
+ }
+ })
+ })
+ .filter(|info| {
// We approximate the coherence rules to only suggest
// traits that are legal to implement by requiring that
// either the type or trait is local. Multi-dispatch means
@@ -2077,7 +2263,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Colon,
Nothing,
}
- let ast_generics = hir.get_generics(id.owner).unwrap();
+ 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)
{
@@ -2236,6 +2422,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
+ /// issue #102320, for `unwrap_or` with closure as argument, suggest `unwrap_or_else`
+ /// FIXME: currently not working for suggesting `map_or_else`, see #102408
+ pub(crate) fn suggest_else_fn_with_closure(
+ &self,
+ err: &mut Diagnostic,
+ expr: &hir::Expr<'_>,
+ found: Ty<'tcx>,
+ expected: Ty<'tcx>,
+ ) -> bool {
+ let Some((_def_id_or_name, output, _inputs)) = self.extract_callable_info(expr, found)
+ else { return false; };
+
+ if !self.can_coerce(output, expected) {
+ return false;
+ }
+
+ let parent = self.tcx.hir().get_parent_node(expr.hir_id);
+ if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) &&
+ let hir::ExprKind::MethodCall(
+ hir::PathSegment { ident: method_name, .. },
+ self_expr,
+ args,
+ ..,
+ ) = call_expr.kind &&
+ let Some(self_ty) = self.typeck_results.borrow().expr_ty_opt(self_expr) {
+ let new_name = Ident {
+ name: Symbol::intern(&format!("{}_else", method_name.as_str())),
+ span: method_name.span,
+ };
+ let probe = self.lookup_probe(
+ expr.span,
+ new_name,
+ self_ty,
+ self_expr,
+ ProbeScope::TraitsInScope,
+ );
+
+ // check the method arguments number
+ if let Ok(pick) = probe &&
+ let fn_sig = self.tcx.fn_sig(pick.item.def_id) &&
+ let fn_args = fn_sig.skip_binder().inputs() &&
+ 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()),
+ "_else",
+ Applicability::MaybeIncorrect,
+ );
+ return true;
+ }
+ }
+ false
+ }
+
/// Checks whether there is a local type somewhere in the chain of
/// autoderefs of `rcvr_ty`.
fn type_derefs_to_local(
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 4754717c2..895739976 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -2,7 +2,7 @@
use super::method::MethodCallee;
use super::{has_expected_num_generic_args, FnCtxt};
-use crate::check::Expectation;
+use crate::Expectation;
use rustc_ast as ast;
use rustc_errors::{self, struct_span_err, Applicability, Diagnostic};
use rustc_hir as hir;
@@ -13,11 +13,12 @@ use rustc_middle::ty::adjustment::{
};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable};
+use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt};
use rustc_type_ir::sty::TyKind::*;
@@ -470,7 +471,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// This has nothing here because it means we did string
// concatenation (e.g., "Hello " + "World!"). This means
// we don't want the note in the else clause to be emitted
- } else if lhs_ty.has_param_types_or_consts() {
+ } else if lhs_ty.has_non_region_param() {
// Look for a TraitPredicate in the Fulfillment errors,
// and use it to generate a suggestion.
//
@@ -511,7 +512,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => None,
};
- self.suggest_restricting_param_bound(
+ self.err_ctxt().suggest_restricting_param_bound(
&mut err,
trait_pred,
output_associated_item,
@@ -656,12 +657,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("cannot apply unary operator `{}`", op.as_str()),
);
- if operand_ty.has_param_types_or_consts() {
+ if operand_ty.has_non_region_param() {
let predicates = errors.iter().filter_map(|error| {
error.obligation.predicate.to_opt_poly_trait_pred()
});
for pred in predicates {
- self.suggest_restricting_param_bound(
+ self.err_ctxt().suggest_restricting_param_bound(
&mut err,
pred,
None,
@@ -677,7 +678,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If the previous expression was a block expression, suggest parentheses
// (turning this into a binary subtraction operation instead.)
// for example, `{2} - 2` -> `({2}) - 2` (see src\test\ui\parser\expr-as-stmt.rs)
- self.tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp);
+ err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
} else {
match actual.kind() {
Uint(_) if op == hir::UnOp::Neg => {
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 8906b622b..ea90da4a6 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -1,6 +1,5 @@
-use crate::check::FnCtxt;
+use crate::FnCtxt;
use rustc_ast as ast;
-
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
@@ -1790,10 +1789,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(),
);
- self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |build| {
- let mut lint = build.build("some fields are not explicitly listed");
+ self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, "some fields are not explicitly listed", |lint| {
lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns));
-
lint.help(
"ensure that all fields are mentioned explicitly by adding the suggested fields",
);
@@ -1801,7 +1798,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"the pattern is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
ty,
));
- lint.emit();
+
+ lint
});
}
diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index 2e0f37eba..ba8cf6926 100644
--- a/compiler/rustc_typeck/src/check/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -1,5 +1,5 @@
-use crate::check::method::MethodCallee;
-use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp};
+use crate::method::MethodCallee;
+use crate::{has_expected_num_generic_args, FnCtxt, PlaceOp};
use rustc_ast as ast;
use rustc_errors::Applicability;
use rustc_hir as hir;
diff --git a/compiler/rustc_typeck/src/check/rvalue_scopes.rs b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
index 22c9e7961..22c9e7961 100644
--- a/compiler/rustc_typeck/src/check/rvalue_scopes.rs
+++ b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 0b207a6c0..4dea40829 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -352,7 +352,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// and that the path can be captured with required capture kind (depending on use in closure,
/// move closure etc.)
///
- /// Returns the set of of adjusted information along with the inferred closure kind and span
+ /// Returns the set of adjusted information along with the inferred closure kind and span
/// associated with the closure kind inference.
///
/// Note that we *always* infer a minimal kind, even if
@@ -749,10 +749,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
closure_hir_id,
closure_head_span,
+ reasons.migration_message(),
|lint| {
- let mut diagnostics_builder = lint.build(
- &reasons.migration_message(),
- );
for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations {
// Labels all the usage of the captured variable and why they are responsible
// for migration being needed
@@ -760,13 +758,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match &lint_note.captures_info {
UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => {
let cause_span = self.tcx.hir().span(*capture_expr_id);
- diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
+ lint.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
self.tcx.hir().name(*var_hir_id),
captured_name,
));
}
UpvarMigrationInfo::CapturingNothing { use_span } => {
- diagnostics_builder.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect",
+ lint.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect",
self.tcx.hir().name(*var_hir_id),
));
}
@@ -781,13 +779,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match &lint_note.captures_info {
UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
- diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
+ lint.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
self.tcx.hir().name(*var_hir_id),
captured_name,
));
}
UpvarMigrationInfo::CapturingNothing { use_span: _ } => {
- diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure",
+ lint.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure",
v = self.tcx.hir().name(*var_hir_id),
));
}
@@ -800,7 +798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match &lint_note.captures_info {
UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
let var_name = self.tcx.hir().name(*var_hir_id);
- diagnostics_builder.span_label(closure_head_span, format!("\
+ lint.span_label(closure_head_span, format!("\
in Rust 2018, this closure implements {missing_trait} \
as `{var_name}` implements {missing_trait}, but in Rust 2021, \
this closure will no longer implement {missing_trait} \
@@ -814,7 +812,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
- diagnostics_builder.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
+ lint.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
let diagnostic_msg = format!(
"add a dummy let to cause {} to be fully captured",
@@ -857,7 +855,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We take the indentation from the next non-empty line.
let line2 = lines.find(|line| !line.is_empty()).unwrap_or_default();
let indent = line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0;
- diagnostics_builder.span_suggestion(
+ lint.span_suggestion(
closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(),
&diagnostic_msg,
format!("\n{indent}{migration_string};"),
@@ -868,7 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// braces, but with more than just the opening
// brace on the first line. We put the `let`
// directly after the `{`.
- diagnostics_builder.span_suggestion(
+ lint.span_suggestion(
closure_body_span.with_lo(closure_body_span.lo() + BytePos(1)).shrink_to_lo(),
&diagnostic_msg,
format!(" {migration_string};"),
@@ -877,7 +875,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
// This is a closure without braces around the body.
// We add braces to add the `let` before the body.
- diagnostics_builder.multipart_suggestion(
+ lint.multipart_suggestion(
&diagnostic_msg,
vec![
(closure_body_span.shrink_to_lo(), format!("{{ {migration_string}; ")),
@@ -887,7 +885,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
} else {
- diagnostics_builder.span_suggestion(
+ lint.span_suggestion(
closure_span,
&diagnostic_msg,
migration_string,
@@ -895,7 +893,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
- diagnostics_builder.emit();
+ lint
},
);
}
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 9ecf34e9a..1e26daa9c 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -2,7 +2,7 @@
// unresolved type variables and replaces "ty_var" types with their
// substitutions.
-use crate::check::FnCtxt;
+use crate::FnCtxt;
use hir::def_id::LocalDefId;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorGuaranteed;
@@ -536,33 +536,37 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
let opaque_types =
self.fcx.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
for (opaque_type_key, decl) in opaque_types {
- let hidden_type = match decl.origin {
- hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
- let ty = self.resolve(decl.hidden_type.ty, &decl.hidden_type.span);
- struct RecursionChecker {
- def_id: LocalDefId,
- }
- impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker {
- type BreakTy = ();
- fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- if let ty::Opaque(def_id, _) = *t.kind() {
- if def_id == self.def_id.to_def_id() {
- return ControlFlow::Break(());
- }
- }
- t.super_visit_with(self)
+ let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span);
+ let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span);
+
+ struct RecursionChecker {
+ def_id: LocalDefId,
+ }
+ impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker {
+ type BreakTy = ();
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if let ty::Opaque(def_id, _) = *t.kind() {
+ if def_id == self.def_id.to_def_id() {
+ return ControlFlow::Break(());
}
}
- if ty
- .visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id })
- .is_break()
- {
- return;
- }
- Some(ty)
+ t.super_visit_with(self)
}
- hir::OpaqueTyOrigin::TyAlias => None,
- };
+ }
+ if hidden_type
+ .visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id })
+ .is_break()
+ {
+ continue;
+ }
+
+ let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
+ opaque_type_key,
+ self.fcx.infcx.tcx,
+ true,
+ decl.origin,
+ );
+
self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
}
}
@@ -700,7 +704,7 @@ impl Locatable for hir::HirId {
/// unresolved types and so forth.
struct Resolver<'cx, 'tcx> {
tcx: TyCtxt<'tcx>,
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
span: &'cx dyn Locatable,
body: &'tcx hir::Body<'tcx>,
@@ -717,27 +721,14 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
Resolver { tcx: fcx.tcx, infcx: fcx, span, body, replaced_with_error: false }
}
- fn report_type_error(&self, t: Ty<'tcx>) {
+ fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) {
if !self.tcx.sess.has_errors().is_some() {
self.infcx
+ .err_ctxt()
.emit_inference_failure_err(
Some(self.body.id()),
self.span.to_span(self.tcx),
- t.into(),
- E0282,
- false,
- )
- .emit();
- }
- }
-
- fn report_const_error(&self, c: ty::Const<'tcx>) {
- if self.tcx.sess.has_errors().is_none() {
- self.infcx
- .emit_inference_failure_err(
- Some(self.body.id()),
- self.span.to_span(self.tcx),
- c.into(),
+ p.into(),
E0282,
false,
)
@@ -782,7 +773,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
}
Err(_) => {
debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
- self.report_type_error(t);
+ self.report_error(t);
self.replaced_with_error = true;
self.tcx().ty_error()
}
@@ -799,7 +790,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
Ok(ct) => self.tcx.erase_regions(ct),
Err(_) => {
debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
- self.report_const_error(ct);
+ self.report_error(ct);
self.replaced_with_error = true;
self.tcx().const_error(ct.ty())
}
diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml
index d3c425a07..179e85f32 100644
--- a/compiler/rustc_incremental/Cargo.toml
+++ b/compiler/rustc_incremental/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
rustc_graphviz = { path = "../rustc_graphviz" }
diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs
index 2c9e21f76..83dd9a67e 100644
--- a/compiler/rustc_incremental/src/lib.rs
+++ b/compiler/rustc_incremental/src/lib.rs
@@ -2,7 +2,6 @@
#![deny(missing_docs)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![cfg_attr(bootstrap, feature(let_else))]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 710c4a01b..79e2d371e 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -149,19 +149,19 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
let crate_items = tcx.hir_crate_items(());
for id in crate_items.items() {
- dirty_clean_visitor.check_item(id.def_id);
+ dirty_clean_visitor.check_item(id.owner_id.def_id);
}
for id in crate_items.trait_items() {
- dirty_clean_visitor.check_item(id.def_id);
+ dirty_clean_visitor.check_item(id.owner_id.def_id);
}
for id in crate_items.impl_items() {
- dirty_clean_visitor.check_item(id.def_id);
+ dirty_clean_visitor.check_item(id.owner_id.def_id);
}
for id in crate_items.foreign_items() {
- dirty_clean_visitor.check_item(id.def_id);
+ dirty_clean_visitor.check_item(id.owner_id.def_id);
}
let mut all_attrs = FindAllAttrs { tcx, found_attrs: vec![] };
@@ -302,7 +302,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
HirNode::ImplItem(item) => match item.kind {
ImplItemKind::Fn(..) => ("Node::ImplItem", LABELS_FN_IN_IMPL),
ImplItemKind::Const(..) => ("NodeImplConst", LABELS_CONST_IN_IMPL),
- ImplItemKind::TyAlias(..) => ("NodeImplType", LABELS_CONST_IN_IMPL),
+ ImplItemKind::Type(..) => ("NodeImplType", LABELS_CONST_IN_IMPL),
},
_ => self.tcx.sess.span_fatal(
attr.span,
diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml
index 8a81a93a9..d8ea5aa80 100644
--- a/compiler/rustc_index/Cargo.toml
+++ b/compiler/rustc_index/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
arrayvec = { version = "0.7", default-features = false }
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index a00d7bd68..23a4c1f06 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -1,9 +1,7 @@
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
#![feature(allow_internal_unstable)]
-#![feature(bench_black_box)]
#![feature(extend_one)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(min_specialization)]
#![feature(new_uninit)]
#![feature(step_trait)]
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index d232a1864..2131d1906 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -1,10 +1,11 @@
use hir::GenericParamKind;
use rustc_errors::{
- fluent, AddSubdiagnostic, Applicability, DiagnosticMessage, DiagnosticStyledString, MultiSpan,
+ fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
+ MultiSpan, SubdiagnosticMessage,
};
use rustc_hir as hir;
use rustc_hir::{FnRetTy, Ty};
-use rustc_macros::SessionDiagnostic;
+use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::{Region, TyCtxt};
use rustc_span::symbol::kw;
use rustc_span::{symbol::Ident, BytePos, Span};
@@ -16,20 +17,20 @@ use crate::infer::error_reporting::{
pub mod note_and_explain;
-#[derive(SessionDiagnostic)]
-#[diag(infer::opaque_hidden_type)]
+#[derive(Diagnostic)]
+#[diag(infer_opaque_hidden_type)]
pub struct OpaqueHiddenTypeDiag {
#[primary_span]
#[label]
pub span: Span,
- #[note(infer::opaque_type)]
+ #[note(opaque_type)]
pub opaque_type: Span,
- #[note(infer::hidden_type)]
+ #[note(hidden_type)]
pub hidden_type: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0282")]
+#[derive(Diagnostic)]
+#[diag(infer_type_annotations_needed, code = "E0282")]
pub struct AnnotationRequired<'a> {
#[primary_span]
pub span: Span,
@@ -46,8 +47,8 @@ pub struct AnnotationRequired<'a> {
}
// Copy of `AnnotationRequired` for E0283
-#[derive(SessionDiagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0283")]
+#[derive(Diagnostic)]
+#[diag(infer_type_annotations_needed, code = "E0283")]
pub struct AmbigousImpl<'a> {
#[primary_span]
pub span: Span,
@@ -64,8 +65,8 @@ pub struct AmbigousImpl<'a> {
}
// Copy of `AnnotationRequired` for E0284
-#[derive(SessionDiagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0284")]
+#[derive(Diagnostic)]
+#[diag(infer_type_annotations_needed, code = "E0284")]
pub struct AmbigousReturn<'a> {
#[primary_span]
pub span: Span,
@@ -81,8 +82,8 @@ pub struct AmbigousReturn<'a> {
pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
}
-#[derive(SessionDiagnostic)]
-#[diag(infer::need_type_info_in_generator, code = "E0698")]
+#[derive(Diagnostic)]
+#[diag(infer_need_type_info_in_generator, code = "E0698")]
pub struct NeedTypeInfoInGenerator<'a> {
#[primary_span]
pub span: Span,
@@ -92,8 +93,8 @@ pub struct NeedTypeInfoInGenerator<'a> {
}
// Used when a better one isn't available
-#[derive(SessionSubdiagnostic)]
-#[label(infer::label_bad)]
+#[derive(Subdiagnostic)]
+#[label(infer_label_bad)]
pub struct InferenceBadError<'a> {
#[primary_span]
pub span: Span,
@@ -106,10 +107,10 @@ pub struct InferenceBadError<'a> {
pub name: String,
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub enum SourceKindSubdiag<'a> {
#[suggestion_verbose(
- infer::source_kind_subdiag_let,
+ infer_source_kind_subdiag_let,
code = ": {type_name}",
applicability = "has-placeholders"
)]
@@ -124,7 +125,7 @@ pub enum SourceKindSubdiag<'a> {
prefix: &'a str,
arg_name: String,
},
- #[label(infer::source_kind_subdiag_generic_label)]
+ #[label(infer_source_kind_subdiag_generic_label)]
GenericLabel {
#[primary_span]
span: Span,
@@ -135,7 +136,7 @@ pub enum SourceKindSubdiag<'a> {
parent_name: String,
},
#[suggestion_verbose(
- infer::source_kind_subdiag_generic_suggestion,
+ infer_source_kind_subdiag_generic_suggestion,
code = "::<{args}>",
applicability = "has-placeholders"
)]
@@ -147,10 +148,10 @@ pub enum SourceKindSubdiag<'a> {
},
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub enum SourceKindMultiSuggestion<'a> {
#[multipart_suggestion_verbose(
- infer::source_kind_fully_qualified,
+ infer_source_kind_fully_qualified,
applicability = "has-placeholders"
)]
FullyQualified {
@@ -163,7 +164,7 @@ pub enum SourceKindMultiSuggestion<'a> {
successor_pos: &'a str,
},
#[multipart_suggestion_verbose(
- infer::source_kind_closure_return,
+ infer_source_kind_closure_return,
applicability = "has-placeholders"
)]
ClosureReturn {
@@ -228,8 +229,11 @@ pub enum RegionOriginNote<'a> {
},
}
-impl AddSubdiagnostic for RegionOriginNote<'_> {
- fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+impl AddToDiagnostic for RegionOriginNote<'_> {
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
let mut label_or_note = |span, msg: DiagnosticMessage| {
let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
@@ -256,7 +260,7 @@ impl AddSubdiagnostic for RegionOriginNote<'_> {
requirement,
expected_found: Some((expected, found)),
} => {
- label_or_note(span, fluent::infer::subtype);
+ label_or_note(span, fluent::infer_subtype);
diag.set_arg("requirement", requirement);
diag.note_expected_found(&"", expected, &"", found);
@@ -265,7 +269,7 @@ impl AddSubdiagnostic for RegionOriginNote<'_> {
// FIXME: this really should be handled at some earlier stage. Our
// handling of region checking when type errors are present is
// *terrible*.
- label_or_note(span, fluent::infer::subtype_2);
+ label_or_note(span, fluent::infer_subtype_2);
diag.set_arg("requirement", requirement);
}
};
@@ -289,13 +293,16 @@ pub enum LifetimeMismatchLabels {
},
}
-impl AddSubdiagnostic for LifetimeMismatchLabels {
- fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+impl AddToDiagnostic for LifetimeMismatchLabels {
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
match self {
LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
- diag.span_label(param_span, fluent::infer::declared_different);
- diag.span_label(ret_span, fluent::infer::nothing);
- diag.span_label(span, fluent::infer::data_returned);
+ diag.span_label(param_span, fluent::infer_declared_different);
+ diag.span_label(ret_span, fluent::infer_nothing);
+ diag.span_label(span, fluent::infer_data_returned);
diag.set_arg("label_var1_exists", label_var1.is_some());
diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
}
@@ -308,13 +315,13 @@ impl AddSubdiagnostic for LifetimeMismatchLabels {
sub: label_var2,
} => {
if hir_equal {
- diag.span_label(ty_sup, fluent::infer::declared_multiple);
- diag.span_label(ty_sub, fluent::infer::nothing);
- diag.span_label(span, fluent::infer::data_lifetime_flow);
+ diag.span_label(ty_sup, fluent::infer_declared_multiple);
+ diag.span_label(ty_sub, fluent::infer_nothing);
+ diag.span_label(span, fluent::infer_data_lifetime_flow);
} else {
- diag.span_label(ty_sup, fluent::infer::types_declared_different);
- diag.span_label(ty_sub, fluent::infer::nothing);
- diag.span_label(span, fluent::infer::data_flows);
+ diag.span_label(ty_sup, fluent::infer_types_declared_different);
+ diag.span_label(ty_sub, fluent::infer_nothing);
+ diag.span_label(span, fluent::infer_data_flows);
diag.set_arg("label_var1_exists", label_var1.is_some());
diag.set_arg(
"label_var1",
@@ -339,8 +346,11 @@ pub struct AddLifetimeParamsSuggestion<'a> {
pub add_note: bool,
}
-impl AddSubdiagnostic for AddLifetimeParamsSuggestion<'_> {
- fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
let mut mk_suggestion = || {
let (
hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
@@ -409,7 +419,7 @@ impl AddSubdiagnostic for AddLifetimeParamsSuggestion<'_> {
}
diag.multipart_suggestion(
- fluent::infer::lifetime_param_suggestion,
+ fluent::infer_lifetime_param_suggestion,
suggestions,
Applicability::MaybeIncorrect,
);
@@ -417,13 +427,13 @@ impl AddSubdiagnostic for AddLifetimeParamsSuggestion<'_> {
true
};
if mk_suggestion() && self.add_note {
- diag.note(fluent::infer::lifetime_param_suggestion_elided);
+ diag.note(fluent::infer_lifetime_param_suggestion_elided);
}
}
}
-#[derive(SessionDiagnostic)]
-#[diag(infer::lifetime_mismatch, code = "E0623")]
+#[derive(Diagnostic)]
+#[diag(infer_lifetime_mismatch, code = "E0623")]
pub struct LifetimeMismatch<'a> {
#[primary_span]
pub span: Span,
@@ -438,53 +448,49 @@ pub struct IntroducesStaticBecauseUnmetLifetimeReq {
pub binding_span: Span,
}
-impl AddSubdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
- fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) {
+impl AddToDiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
+ fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, _: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
self.unmet_requirements
- .push_span_label(self.binding_span, fluent::infer::msl_introduces_static);
- diag.span_note(self.unmet_requirements, fluent::infer::msl_unmet_req);
+ .push_span_label(self.binding_span, fluent::infer_msl_introduces_static);
+ diag.span_note(self.unmet_requirements, fluent::infer_msl_unmet_req);
}
}
-pub struct ImplNote {
- pub impl_span: Option<Span>,
-}
-
-impl AddSubdiagnostic for ImplNote {
- fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
- match self.impl_span {
- Some(span) => diag.span_note(span, fluent::infer::msl_impl_note),
- None => diag.note(fluent::infer::msl_impl_note),
- };
- }
-}
-
-pub enum TraitSubdiag {
- Note { span: Span },
- Sugg { span: Span },
+// FIXME(#100717): replace with a `Option<Span>` when subdiagnostic supports that
+#[derive(Subdiagnostic)]
+pub enum DoesNotOutliveStaticFromImpl {
+ #[note(infer_does_not_outlive_static_from_impl)]
+ Spanned {
+ #[primary_span]
+ span: Span,
+ },
+ #[note(infer_does_not_outlive_static_from_impl)]
+ Unspanned,
}
-// FIXME(#100717) used in `Vec<TraitSubdiag>` so requires eager translation/list support
-impl AddSubdiagnostic for TraitSubdiag {
- fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
- match self {
- TraitSubdiag::Note { span } => {
- diag.span_note(span, "this has an implicit `'static` lifetime requirement");
- }
- TraitSubdiag::Sugg { span } => {
- diag.span_suggestion_verbose(
- span,
- "consider relaxing the implicit `'static` requirement",
- " + '_".to_owned(),
- rustc_errors::Applicability::MaybeIncorrect,
- );
- }
- }
- }
+#[derive(Subdiagnostic)]
+pub enum ImplicitStaticLifetimeSubdiag {
+ #[note(infer_implicit_static_lifetime_note)]
+ Note {
+ #[primary_span]
+ span: Span,
+ },
+ #[suggestion_verbose(
+ infer_implicit_static_lifetime_suggestion,
+ code = " + '_",
+ applicability = "maybe-incorrect"
+ )]
+ Sugg {
+ #[primary_span]
+ span: Span,
+ },
}
-#[derive(SessionDiagnostic)]
-#[diag(infer::mismatched_static_lifetime)]
+#[derive(Diagnostic)]
+#[diag(infer_mismatched_static_lifetime)]
pub struct MismatchedStaticLifetime<'a> {
#[primary_span]
pub cause_span: Span,
@@ -493,7 +499,7 @@ pub struct MismatchedStaticLifetime<'a> {
#[subdiagnostic]
pub expl: Option<note_and_explain::RegionExplanation<'a>>,
#[subdiagnostic]
- pub impl_note: ImplNote,
- #[subdiagnostic]
- pub trait_subdiags: Vec<TraitSubdiag>,
+ pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl,
+ #[subdiagnostic(eager)]
+ pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,
}
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
index 7e051835b..6a29d8562 100644
--- a/compiler/rustc_infer/src/errors/note_and_explain.rs
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -1,5 +1,7 @@
use crate::infer::error_reporting::nice_region_error::find_anon_type;
-use rustc_errors::{self, fluent, AddSubdiagnostic, IntoDiagnosticArg};
+use rustc_errors::{
+ self, fluent, AddToDiagnostic, Diagnostic, IntoDiagnosticArg, SubdiagnosticMessage,
+};
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{symbol::kw, Span};
@@ -158,12 +160,15 @@ impl RegionExplanation<'_> {
}
}
-impl AddSubdiagnostic for RegionExplanation<'_> {
- fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+impl AddToDiagnostic for RegionExplanation<'_> {
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
if let Some(span) = self.desc.span {
- diag.span_note(span, fluent::infer::region_explanation);
+ diag.span_note(span, fluent::infer_region_explanation);
} else {
- diag.note(fluent::infer::region_explanation);
+ diag.note(fluent::infer_region_explanation);
}
self.desc.add_to(diag);
diag.set_arg("pref_kind", self.prefix);
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 00e238648..5ff3779fa 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -31,7 +31,7 @@ use rustc_middle::ty::relate::{Relate, TypeRelation};
use rustc_middle::ty::{Const, ImplSubject};
pub struct At<'a, 'tcx> {
- pub infcx: &'a InferCtxt<'a, 'tcx>,
+ pub infcx: &'a InferCtxt<'tcx>,
pub cause: &'a ObligationCause<'tcx>,
pub param_env: ty::ParamEnv<'tcx>,
/// Whether we should define opaque types
@@ -48,9 +48,9 @@ pub struct Trace<'a, 'tcx> {
trace: TypeTrace<'tcx>,
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
#[inline]
- pub fn at(
+ pub fn at<'a>(
&'a self,
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -66,7 +66,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
tcx: self.tcx,
defining_use_anchor: self.defining_use_anchor,
considering_regions: self.considering_regions,
- in_progress_typeck_results: self.in_progress_typeck_results,
inner: self.inner.clone(),
skip_leak_check: self.skip_leak_check.clone(),
lexical_region_resolutions: self.lexical_region_resolutions.clone(),
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 9488d0a6c..a3ff70363 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -20,7 +20,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_index::vec::Idx;
use smallvec::SmallVec;
-impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Canonicalizes a query value `V`. When we canonicalize a query,
/// we not only canonicalize unbound inference variables, but we
/// *also* replace all free regions whatsoever. So for example a
@@ -316,7 +316,7 @@ impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic {
}
struct Canonicalizer<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
tcx: TyCtxt<'tcx>,
variables: SmallVec<[CanonicalVarInfo<'tcx>; 8]>,
query_state: &'cx mut OriginalQueryValues<'tcx>,
@@ -521,7 +521,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
/// `canonicalize_query` and `canonicalize_response`.
fn canonicalize<V>(
value: V,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
tcx: TyCtxt<'tcx>,
canonicalize_region_mode: &dyn CanonicalizeMode,
query_state: &mut OriginalQueryValues<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index a9294a85e..06ca2534d 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -36,7 +36,7 @@ mod canonicalizer;
pub mod query_response;
mod substitute;
-impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Creates a substitution S for the canonical value with fresh
/// inference variables and applies it to the canonical value.
/// Returns both the instantiated result *and* the substitution S.
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 56e834898..a299a3e57 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -16,8 +16,8 @@ use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelating
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
use crate::traits::query::{Fallible, NoSolution};
-use crate::traits::TraitEngine;
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
+use crate::traits::{PredicateObligations, TraitEngine};
use rustc_data_structures::captures::Captures;
use rustc_index::vec::Idx;
use rustc_index::vec::IndexVec;
@@ -32,7 +32,7 @@ use rustc_span::Span;
use std::fmt::Debug;
use std::iter;
-impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// This method is meant to be invoked as the final step of a canonical query
/// implementation. It is given:
///
@@ -509,7 +509,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
for &(a, b) in &query_response.value.opaque_types {
let a = substitute_value(self.tcx, &result_subst, a);
let b = substitute_value(self.tcx, &result_subst, b);
- obligations.extend(self.handle_opaque_type(a, b, true, cause, param_env)?.obligations);
+ obligations.extend(self.at(cause, param_env).eq(a, b)?.obligations);
}
Ok(InferOk { value: result_subst, obligations })
@@ -677,7 +677,7 @@ pub fn make_query_region_constraints<'tcx>(
}
struct QueryTypeRelatingDelegate<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
obligations: &'a mut Vec<PredicateObligation<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
cause: &'a ObligationCause<'tcx>,
@@ -741,17 +741,11 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
true
}
- fn register_opaque_type(
+ fn register_opaque_type_obligations(
&mut self,
- a: Ty<'tcx>,
- b: Ty<'tcx>,
- a_is_expected: bool,
+ obligations: PredicateObligations<'tcx>,
) -> Result<(), TypeError<'tcx>> {
- self.obligations.extend(
- self.infcx
- .handle_opaque_type(a, b, a_is_expected, &self.cause, self.param_env)?
- .obligations,
- );
+ self.obligations.extend(obligations);
Ok(())
}
}
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index c406df9e4..b5427f639 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -43,7 +43,7 @@ use rustc_span::{Span, DUMMY_SP};
#[derive(Clone)]
pub struct CombineFields<'infcx, 'tcx> {
- pub infcx: &'infcx InferCtxt<'infcx, 'tcx>,
+ pub infcx: &'infcx InferCtxt<'tcx>,
pub trace: TypeTrace<'tcx>,
pub cause: Option<ty::relate::Cause>,
pub param_env: ty::ParamEnv<'tcx>,
@@ -63,7 +63,7 @@ pub enum RelationDir {
EqTo,
}
-impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
pub fn super_combine_tys<R>(
&self,
relation: &mut R,
@@ -147,11 +147,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
ty::ConstKind::Infer(InferConst::Var(a_vid)),
ty::ConstKind::Infer(InferConst::Var(b_vid)),
) => {
- self.inner
- .borrow_mut()
- .const_unification_table()
- .unify_var_var(a_vid, b_vid)
- .map_err(|e| const_unification_error(a_is_expected, e))?;
+ self.inner.borrow_mut().const_unification_table().union(a_vid, b_vid);
return Ok(a);
}
@@ -246,21 +242,17 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
let value = ConstInferUnifier { infcx: self, span, param_env, for_universe, target_vid }
.relate(ct, ct)?;
- self.inner
- .borrow_mut()
- .const_unification_table()
- .unify_var_value(
- target_vid,
- ConstVarValue {
- origin: ConstVariableOrigin {
- kind: ConstVariableOriginKind::ConstInference,
- span: DUMMY_SP,
- },
- val: ConstVariableValue::Known { value },
+ self.inner.borrow_mut().const_unification_table().union_value(
+ target_vid,
+ ConstVarValue {
+ origin: ConstVariableOrigin {
+ kind: ConstVariableOriginKind::ConstInference,
+ span: DUMMY_SP,
},
- )
- .map(|()| value)
- .map_err(|e| const_unification_error(vid_is_expected, e))
+ val: ConstVariableValue::Known { value },
+ },
+ );
+ Ok(value)
}
fn unify_integral_variable(
@@ -460,7 +452,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
}
struct Generalizer<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
/// The span, used when creating new type variables and things.
cause: &'cx ObligationCause<'tcx>,
@@ -742,9 +734,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
}
}
}
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
- assert_eq!(promoted, ());
-
+ ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
let substs = self.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
@@ -753,7 +743,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
)?;
Ok(self.tcx().mk_const(ty::ConstS {
ty: c.ty(),
- kind: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
+ kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }),
}))
}
_ => relate::super_relate_consts(self, c, c),
@@ -768,13 +758,6 @@ pub trait ConstEquateRelation<'tcx>: TypeRelation<'tcx> {
fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
}
-pub fn const_unification_error<'tcx>(
- a_is_expected: bool,
- (a, b): (ty::Const<'tcx>, ty::Const<'tcx>),
-) -> TypeError<'tcx> {
- TypeError::ConstMismatch(ExpectedFound::new(a_is_expected, a, b))
-}
-
fn int_unification_error<'tcx>(
a_is_expected: bool,
v: (ty::IntVarValue, ty::IntVarValue),
@@ -792,7 +775,7 @@ fn float_unification_error<'tcx>(
}
struct ConstInferUnifier<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
span: Span,
@@ -964,9 +947,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
}
}
}
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
- assert_eq!(promoted, ());
-
+ ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
let substs = self.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
@@ -976,7 +957,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
Ok(self.tcx().mk_const(ty::ConstS {
ty: c.ty(),
- kind: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
+ kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }),
}))
}
_ => relate::super_relate_consts(self, c, c),
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index 3b1798ca7..59728148a 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -110,6 +110,25 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
.obligations,
);
}
+ // Optimization of GeneratorWitness relation since we know that all
+ // free regions are replaced with bound regions during construction.
+ // This greatly speeds up equating of GeneratorWitness.
+ (&ty::GeneratorWitness(a_types), &ty::GeneratorWitness(b_types)) => {
+ let a_types = infcx.tcx.anonymize_bound_vars(a_types);
+ let b_types = infcx.tcx.anonymize_bound_vars(b_types);
+ if a_types.bound_vars() == b_types.bound_vars() {
+ let (a_types, b_types) = infcx.replace_bound_vars_with_placeholders(
+ a_types.map_bound(|a_types| (a_types, b_types.skip_binder())),
+ );
+ for (a, b) in std::iter::zip(a_types, b_types) {
+ self.relate(a, b)?;
+ }
+ } else {
+ return Err(ty::error::TypeError::Sorts(ty::relate::expected_found(
+ self, a, b,
+ )));
+ }
+ }
_ => {
self.fields.infcx.super_combine_tys(self, a, b)?;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index eb5afe828..9ff703e52 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -51,6 +51,7 @@ use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePa
use crate::infer;
use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
+use crate::infer::ExpectedFound;
use crate::traits::error_reporting::report_object_safety_error;
use crate::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
@@ -69,12 +70,12 @@ use rustc_middle::dep_graph::DepContext;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
use rustc_middle::ty::{
- self, error::TypeError, Binder, List, Region, Subst, Ty, TyCtxt, TypeFoldable,
- TypeSuperVisitable, TypeVisitable,
+ self, error::TypeError, Binder, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
+ TypeVisitable,
};
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
use rustc_target::spec::abi;
-use std::ops::ControlFlow;
+use std::ops::{ControlFlow, Deref};
use std::{cmp, fmt, iter};
mod note;
@@ -84,6 +85,31 @@ pub use need_type_info::TypeAnnotationNeeded;
pub mod nice_region_error;
+/// A helper for building type related errors. The `typeck_results`
+/// field is only populated during an in-progress typeck.
+/// Get an instance by calling `InferCtxt::err` or `FnCtxt::infer_err`.
+pub struct TypeErrCtxt<'a, 'tcx> {
+ pub infcx: &'a InferCtxt<'tcx>,
+ pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
+}
+
+impl TypeErrCtxt<'_, '_> {
+ /// This is just to avoid a potential footgun of accidentally
+ /// dropping `typeck_results` by calling `InferCtxt::err_ctxt`
+ #[deprecated(note = "you already have a `TypeErrCtxt`")]
+ #[allow(unused)]
+ pub fn err_ctxt(&self) -> ! {
+ bug!("called `err_ctxt` on `TypeErrCtxt`. Try removing the call");
+ }
+}
+
+impl<'tcx> Deref for TypeErrCtxt<'_, 'tcx> {
+ type Target = InferCtxt<'tcx>;
+ fn deref(&self) -> &InferCtxt<'tcx> {
+ &self.infcx
+ }
+}
+
pub(super) fn note_and_explain_region<'tcx>(
tcx: TyCtxt<'tcx>,
err: &mut Diagnostic,
@@ -303,7 +329,38 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
err
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
+ pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Binder<'tcx, Ty<'tcx>>> {
+ if let ty::Opaque(def_id, substs) = ty.kind() {
+ let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
+ // Future::Output
+ let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
+
+ let bounds = self.tcx.bound_explicit_item_bounds(*def_id);
+
+ for (predicate, _) in bounds.subst_iter_copied(self.tcx, substs) {
+ let output = predicate
+ .kind()
+ .map_bound(|kind| match kind {
+ ty::PredicateKind::Projection(projection_predicate)
+ if projection_predicate.projection_ty.item_def_id == item_def_id =>
+ {
+ projection_predicate.term.ty()
+ }
+ _ => None,
+ })
+ .transpose();
+ if output.is_some() {
+ // We don't account for multiple `Future::Output = Ty` constraints.
+ return output;
+ }
+ }
+ }
+ None
+ }
+}
+
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
pub fn report_region_errors(
&self,
generic_param_scope: LocalDefId,
@@ -577,13 +634,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
{
// don't show type `_`
if span.desugaring_kind() == Some(DesugaringKind::ForLoop)
- && let ty::Adt(def, substs) = ty.kind()
- && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
+ && let ty::Adt(def, substs) = ty.kind()
+ && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
{
err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0)));
} else {
- err.span_label(span, format!("this expression has type `{}`", ty));
- }
+ err.span_label(span, format!("this expression has type `{}`", ty));
+ }
}
if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
&& ty.is_box() && ty.boxed_ty() == found
@@ -619,8 +676,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
let arg_expr = args.first().expect("try desugaring call w/out arg");
- self.in_progress_typeck_results.and_then(|typeck_results| {
- typeck_results.borrow().expr_ty_opt(arg_expr)
+ self.typeck_results.as_ref().and_then(|typeck_results| {
+ typeck_results.expr_ty_opt(arg_expr)
})
} else {
bug!("try desugaring w/out call expr as scrutinee");
@@ -726,10 +783,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
_ => {
if let ObligationCauseCode::BindingObligation(_, span)
| ObligationCauseCode::ExprBindingObligation(_, span, ..)
- = cause.code().peel_derives()
+ = cause.code().peel_derives()
&& let TypeError::RegionsPlaceholderMismatch = terr
{
- err.span_note(*span, "the lifetime requirement is introduced here");
+ err.span_note( * span,
+ "the lifetime requirement is introduced here");
}
}
}
@@ -1653,8 +1711,114 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
),
Mismatch::Fixed(s) => (s.into(), s.into(), None),
};
- match (&terr, expected == found) {
- (TypeError::Sorts(values), extra) => {
+
+ enum Similar<'tcx> {
+ Adts { expected: ty::AdtDef<'tcx>, found: ty::AdtDef<'tcx> },
+ PrimitiveFound { expected: ty::AdtDef<'tcx>, found: Ty<'tcx> },
+ PrimitiveExpected { expected: Ty<'tcx>, found: ty::AdtDef<'tcx> },
+ }
+
+ let similarity = |ExpectedFound { expected, found }: ExpectedFound<Ty<'tcx>>| {
+ if let ty::Adt(expected, _) = expected.kind() && let Some(primitive) = found.primitive_symbol() {
+ let path = self.tcx.def_path(expected.did()).data;
+ let name = path.last().unwrap().data.get_opt_name();
+ if name == Some(primitive) {
+ return Some(Similar::PrimitiveFound { expected: *expected, found });
+ }
+ } else if let Some(primitive) = expected.primitive_symbol() && let ty::Adt(found, _) = found.kind() {
+ let path = self.tcx.def_path(found.did()).data;
+ let name = path.last().unwrap().data.get_opt_name();
+ if name == Some(primitive) {
+ return Some(Similar::PrimitiveExpected { expected, found: *found });
+ }
+ } else if let ty::Adt(expected, _) = expected.kind() && let ty::Adt(found, _) = found.kind() {
+ if !expected.did().is_local() && expected.did().krate == found.did().krate {
+ // Most likely types from different versions of the same crate
+ // are in play, in which case this message isn't so helpful.
+ // A "perhaps two different versions..." error is already emitted for that.
+ return None;
+ }
+ let f_path = self.tcx.def_path(found.did()).data;
+ let e_path = self.tcx.def_path(expected.did()).data;
+
+ if let (Some(e_last), Some(f_last)) = (e_path.last(), f_path.last()) && e_last == f_last {
+ return Some(Similar::Adts{expected: *expected, found: *found});
+ }
+ }
+ None
+ };
+
+ match terr {
+ // If two types mismatch but have similar names, mention that specifically.
+ TypeError::Sorts(values) if let Some(s) = similarity(values) => {
+ let diagnose_primitive =
+ |prim: Ty<'tcx>,
+ shadow: Ty<'tcx>,
+ defid: DefId,
+ diagnostic: &mut Diagnostic| {
+ let name = shadow.sort_string(self.tcx);
+ diagnostic.note(format!(
+ "{prim} and {name} have similar names, but are actually distinct types"
+ ));
+ diagnostic
+ .note(format!("{prim} is a primitive defined by the language"));
+ let def_span = self.tcx.def_span(defid);
+ let msg = if defid.is_local() {
+ format!("{name} is defined in the current crate")
+ } else {
+ let crate_name = self.tcx.crate_name(defid.krate);
+ format!("{name} is defined in crate `{crate_name}")
+ };
+ diagnostic.span_note(def_span, msg);
+ };
+
+ let diagnose_adts =
+ |expected_adt : ty::AdtDef<'tcx>,
+ found_adt: ty::AdtDef<'tcx>,
+ diagnostic: &mut Diagnostic| {
+ let found_name = values.found.sort_string(self.tcx);
+ let expected_name = values.expected.sort_string(self.tcx);
+
+ let found_defid = found_adt.did();
+ let expected_defid = expected_adt.did();
+
+ diagnostic.note(format!("{found_name} and {expected_name} have similar names, but are actually distinct types"));
+ for (defid, name) in
+ [(found_defid, found_name), (expected_defid, expected_name)]
+ {
+ let def_span = self.tcx.def_span(defid);
+
+ let msg = if found_defid.is_local() && expected_defid.is_local() {
+ let module = self
+ .tcx
+ .parent_module_from_def_id(defid.expect_local())
+ .to_def_id();
+ let module_name = self.tcx.def_path(module).to_string_no_crate_verbose();
+ format!("{name} is defined in module `crate{module_name}` of the current crate")
+ } else if defid.is_local() {
+ format!("{name} is defined in the current crate")
+ } else {
+ let crate_name = self.tcx.crate_name(defid.krate);
+ format!("{name} is defined in crate `{crate_name}`")
+ };
+ diagnostic.span_note(def_span, msg);
+ }
+ };
+
+ match s {
+ Similar::Adts{expected, found} => {
+ diagnose_adts(expected, found, diag)
+ }
+ Similar::PrimitiveFound{expected, found: prim} => {
+ diagnose_primitive(prim, values.expected, expected.did(), diag)
+ }
+ Similar::PrimitiveExpected{expected: prim, found} => {
+ diagnose_primitive(prim, values.found, found.did(), diag)
+ }
+ }
+ }
+ TypeError::Sorts(values) => {
+ let extra = expected == found;
let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
(true, ty::Opaque(def_id, _)) => {
let sm = self.tcx.sess.source_map();
@@ -1707,10 +1871,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
);
}
}
- (TypeError::ObjectUnsafeCoercion(_), _) => {
+ TypeError::ObjectUnsafeCoercion(_) => {
diag.note_unsuccessful_coercion(found, expected);
}
- (_, _) => {
+ _ => {
debug!(
"note_type_err: exp_found={:?}, expected={:?} found={:?}",
exp_found, expected, found
@@ -1755,7 +1919,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// In some (most?) cases cause.body_id points to actual body, but in some cases
// it's an actual definition. According to the comments (e.g. in
- // librustc_typeck/check/compare_method.rs:compare_predicate_entailment) the latter
+ // rustc_hir_analysis/check/compare_method.rs:compare_predicate_entailment) the latter
// is relied upon by some other code. This might (or might not) need cleanup.
let body_owner_def_id =
self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| {
@@ -1847,36 +2011,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
- pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Binder<'tcx, Ty<'tcx>>> {
- if let ty::Opaque(def_id, substs) = ty.kind() {
- let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
- // Future::Output
- let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
-
- let bounds = self.tcx.bound_explicit_item_bounds(*def_id);
-
- for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
- let predicate = predicate.subst(self.tcx, substs);
- let output = predicate
- .kind()
- .map_bound(|kind| match kind {
- ty::PredicateKind::Projection(projection_predicate)
- if projection_predicate.projection_ty.item_def_id == item_def_id =>
- {
- projection_predicate.term.ty()
- }
- _ => None,
- })
- .transpose();
- if output.is_some() {
- // We don't account for multiple `Future::Output = Ty` constraints.
- return output;
- }
- }
- }
- None
- }
-
/// A possible error is to forget to add `.await` when using futures:
///
/// ```compile_fail,E0308
@@ -2051,8 +2185,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
diag: &mut Diagnostic,
) {
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
+ && let Some(msg) = self.should_suggest_as_ref(exp_found.expected, exp_found.found)
+ {
+ diag.span_suggestion(
+ span,
+ msg,
+ // HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&`
+ format!("{}.as_ref()", snippet.trim_start_matches('&')),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
+ pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> {
if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) =
- (exp_found.expected.kind(), exp_found.found.kind())
+ (expected.kind(), found.kind())
{
if let ty::Adt(found_def, found_substs) = *found_ty.kind() {
if exp_def == &found_def {
@@ -2090,21 +2238,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
_ => show_suggestion = false,
}
}
- if let (Ok(snippet), true) =
- (self.tcx.sess.source_map().span_to_snippet(span), show_suggestion)
- {
- diag.span_suggestion(
- span,
- *msg,
- // HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&`
- format!("{}.as_ref()", snippet.trim_start_matches('&')),
- Applicability::MachineApplicable,
- );
+ if show_suggestion {
+ return Some(*msg);
}
}
}
}
}
+ None
}
pub fn report_and_explain_type_error(
@@ -2130,6 +2271,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str)
}
FailureCode::Error0308(failure_str) => {
+ fn escape_literal(s: &str) -> String {
+ let mut escaped = String::with_capacity(s.len());
+ let mut chrs = s.chars().peekable();
+ while let Some(first) = chrs.next() {
+ match (first, chrs.peek()) {
+ ('\\', Some(&delim @ '"') | Some(&delim @ '\'')) => {
+ escaped.push('\\');
+ escaped.push(delim);
+ chrs.next();
+ }
+ ('"' | '\'', _) => {
+ escaped.push('\\');
+ escaped.push(first)
+ }
+ (c, _) => escaped.push(c),
+ };
+ }
+ escaped
+ }
let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str);
if let Some((expected, found)) = trace.values.ty() {
match (expected.kind(), found.kind()) {
@@ -2151,7 +2311,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
err.span_suggestion(
span,
"if you meant to write a `char` literal, use single quotes",
- format!("'{}'", code),
+ format!("'{}'", escape_literal(code)),
Applicability::MachineApplicable,
);
}
@@ -2166,7 +2326,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
err.span_suggestion(
span,
"if you meant to write a `str` literal, use double quotes",
- format!("\"{}\"", code),
+ format!("\"{}\"", escape_literal(code)),
Applicability::MachineApplicable,
);
}
@@ -2317,7 +2477,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin: Option<SubregionOrigin<'tcx>>,
bound_kind: GenericKind<'tcx>,
sub: Region<'tcx>,
- ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
// Attempt to obtain the span of the parameter so we can
// suggest adding an explicit lifetime bound to it.
let generics = self.tcx.generics_of(generic_param_scope);
@@ -2333,7 +2493,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// We do this to avoid suggesting code that ends up as `T: 'a'b`,
// instead we suggest `T: 'a + 'b` in that case.
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- let ast_generics = self.tcx.hir().get_generics(hir_id.owner);
+ let ast_generics = self.tcx.hir().get_generics(hir_id.owner.def_id);
let bounds =
ast_generics.and_then(|g| g.bounds_span_for_suggestions(def_id));
// `sp` only covers `T`, change it so that it covers
@@ -2374,6 +2534,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let labeled_user_string = match bound_kind {
GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
GenericKind::Projection(ref p) => format!("the associated type `{}`", p),
+ GenericKind::Opaque(def_id, substs) => {
+ format!("the opaque type `{}`", self.tcx.def_path_str_with_substs(def_id, substs))
+ }
};
if let Some(SubregionOrigin::CompareImplItemObligation {
@@ -2453,7 +2616,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
for h in self.tcx.hir().parent_iter(param.hir_id) {
break 'origin match h.1 {
Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::TyAlias(..),
+ kind: hir::ImplItemKind::Type(..),
generics,
..
})
@@ -2692,7 +2855,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
-struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'a, 'tcx>);
+struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'tcx>);
impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
@@ -2779,7 +2942,7 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
}
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
fn report_inference_failure(
&self,
var_origin: RegionVariableOrigin,
@@ -2967,7 +3130,7 @@ impl TyCategory {
}
}
-impl<'tcx> InferCtxt<'_, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Given a [`hir::Block`], get the span of its last expression or
/// statement, peeling off any inner blocks.
pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span {
@@ -2994,7 +3157,9 @@ impl<'tcx> InferCtxt<'_, 'tcx> {
_ => rustc_span::DUMMY_SP,
}
}
+}
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
/// Be helpful when the user wrote `{... expr; }` and taking the `;` off
/// is enough to fix the error.
pub fn could_remove_semicolon(
@@ -3011,7 +3176,7 @@ impl<'tcx> InferCtxt<'_, 'tcx> {
let hir::StmtKind::Semi(ref last_expr) = last_stmt.kind else {
return None;
};
- let last_expr_ty = self.in_progress_typeck_results?.borrow().expr_ty_opt(*last_expr)?;
+ let last_expr_ty = self.typeck_results.as_ref()?.expr_ty_opt(*last_expr)?;
let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) {
_ if last_expr_ty.references_error() => return None,
_ if self.same_type_modulo_infer(last_expr_ty, expected_ty) => {
@@ -3094,8 +3259,9 @@ impl<'tcx> InferCtxt<'_, 'tcx> {
let mut find_compatible_candidates = |pat: &hir::Pat<'_>| {
if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind
&& let Some(pat_ty) = self
- .in_progress_typeck_results
- .and_then(|typeck_results| typeck_results.borrow().node_type_opt(*hir_id))
+ .typeck_results
+ .as_ref()
+ .and_then(|typeck_results| typeck_results.node_type_opt(*hir_id))
{
let pat_ty = self.resolve_vars_if_possible(pat_ty);
if self.same_type_modulo_infer(pat_ty, expected_ty)
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 cb2be9358..7b3178e61 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
@@ -2,8 +2,10 @@ use crate::errors::{
AmbigousImpl, AmbigousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
SourceKindMultiSuggestion, SourceKindSubdiag,
};
+use crate::infer::error_reporting::TypeErrCtxt;
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::InferCtxt;
+use rustc_errors::IntoDiagnostic;
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg};
use rustc_hir as hir;
use rustc_hir::def::Res;
@@ -15,10 +17,9 @@ use rustc_middle::hir::nested_filter;
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
use rustc_middle::ty::{self, DefIdTree, InferConst};
+use rustc_middle::ty::{GenericArg, GenericArgKind, SubstsRef};
use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults};
-use rustc_session::SessionDiagnostic;
use rustc_span::symbol::{kw, Ident};
use rustc_span::{BytePos, Span};
use std::borrow::Cow;
@@ -151,7 +152,7 @@ impl UnderspecifiedArgKind {
}
}
-fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'_, 'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> {
+fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> {
let mut printer = FmtPrinter::new(infcx.tcx, ns);
let ty_getter = move |ty_vid| {
if infcx.probe_ty_var(ty_vid).is_ok() {
@@ -182,7 +183,7 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'_, 'tcx>, ns: Namespace) -> FmtPr
printer
}
-fn ty_to_string<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
+fn ty_to_string<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String {
let printer = fmt_printer(infcx, Namespace::TypeNS);
let ty = infcx.resolve_vars_if_possible(ty);
match ty.kind() {
@@ -201,7 +202,7 @@ fn ty_to_string<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
/// We don't want to directly use `ty_to_string` for closures as their type isn't really
/// something users are familiar with. Directly printing the `fn_sig` of closures also
/// doesn't work as they actually use the "rust-call" API.
-fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
+fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String {
let ty::Closure(_, substs) = ty.kind() else { unreachable!() };
let fn_sig = substs.as_closure().sig();
let args = fn_sig
@@ -225,7 +226,7 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String
format!("fn({}){}", args, ret)
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Extracts data used by diagnostic for either types or constants
/// which were stuck during inference.
pub fn extract_inference_diagnostics_data(
@@ -317,7 +318,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
- /// Used as a fallback in [InferCtxt::emit_inference_failure_err]
+ /// Used as a fallback in [TypeErrCtxt::emit_inference_failure_err]
/// in case we weren't able to get a better error.
fn bad_inference_failure_err(
&self,
@@ -364,7 +365,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
}
}
+}
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
pub fn emit_inference_failure_err(
&self,
body_id: Option<hir::BodyId>,
@@ -376,14 +379,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let arg = self.resolve_vars_if_possible(arg);
let arg_data = self.extract_inference_diagnostics_data(arg, None);
- let Some(typeck_results) = self.in_progress_typeck_results else {
+ let Some(typeck_results) = &self.typeck_results else {
// If we don't have any typeck results we're outside
// of a body, so we won't be able to get better info
// here.
return self.bad_inference_failure_err(failure_span, arg_data, error_code);
};
- let typeck_results = typeck_results.borrow();
- let typeck_results = &typeck_results;
let mut local_visitor = FindInferSourceVisitor::new(&self, typeck_results, arg);
if let Some(body_id) = body_id {
@@ -435,6 +436,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
generics_def_id,
def_id: _,
generic_args,
+ have_turbofish,
} => {
let generics = self.tcx.generics_of(generics_def_id);
let is_type = matches!(arg.unpack(), GenericArgKind::Type(_));
@@ -482,11 +484,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.unwrap()
.into_buffer();
- infer_subdiags.push(SourceKindSubdiag::GenericSuggestion {
- span: insert_span,
- arg_count: generic_args.len(),
- args,
- });
+ if !have_turbofish {
+ infer_subdiags.push(SourceKindSubdiag::GenericSuggestion {
+ span: insert_span,
+ arg_count: generic_args.len(),
+ args,
+ });
+ }
}
InferSourceKind::FullyQualifiedMethodCall { receiver, successor, substs, def_id } => {
let printer = fmt_printer(self, Namespace::ValueNS);
@@ -560,7 +564,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
}
}
+}
+impl<'tcx> InferCtxt<'tcx> {
pub fn need_type_info_err_in_generator(
&self,
kind: hir::GeneratorKind,
@@ -616,6 +622,7 @@ enum InferSourceKind<'tcx> {
generics_def_id: DefId,
def_id: DefId,
generic_args: &'tcx [GenericArg<'tcx>],
+ have_turbofish: bool,
},
FullyQualifiedMethodCall {
receiver: &'tcx Expr<'tcx>,
@@ -650,7 +657,7 @@ impl<'tcx> InferSource<'tcx> {
}
impl<'tcx> InferSourceKind<'tcx> {
- fn ty_localized_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> (&'static str, String) {
+ fn ty_localized_msg(&self, infcx: &InferCtxt<'tcx>) -> (&'static str, String) {
match *self {
InferSourceKind::LetBinding { ty, .. }
| InferSourceKind::ClosureArg { ty, .. }
@@ -676,6 +683,7 @@ struct InsertableGenericArgs<'tcx> {
substs: SubstsRef<'tcx>,
generics_def_id: DefId,
def_id: DefId,
+ have_turbofish: bool,
}
/// A visitor which searches for the "best" spot to use in the inference error.
@@ -686,7 +694,7 @@ struct InsertableGenericArgs<'tcx> {
/// While doing so, the currently best spot is stored in `infer_source`.
/// For details on how we rank spots, see [Self::source_cost]
struct FindInferSourceVisitor<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
typeck_results: &'a TypeckResults<'tcx>,
target: GenericArg<'tcx>,
@@ -698,7 +706,7 @@ struct FindInferSourceVisitor<'a, 'tcx> {
impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
fn new(
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
typeck_results: &'a TypeckResults<'tcx>,
target: GenericArg<'tcx>,
) -> Self {
@@ -894,11 +902,18 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
// impl is currently the `DefId` of `Output` in the trait definition
// which makes this somewhat difficult and prevents us from just
// using `self.path_inferred_subst_iter` here.
- hir::ExprKind::Struct(&hir::QPath::Resolved(_self_ty, path), _, _) => {
- if let Some(ty) = self.opt_node_type(expr.hir_id) {
- if let ty::Adt(_, substs) = ty.kind() {
- return Box::new(self.resolved_path_inferred_subst_iter(path, substs));
- }
+ hir::ExprKind::Struct(&hir::QPath::Resolved(_self_ty, path), _, _)
+ // FIXME(TaKO8Ki): Ideally we should support this. For that
+ // we have to map back from the self type to the
+ // type alias though. That's difficult.
+ //
+ // See the `need_type_info/issue-103053.rs` test for
+ // a example.
+ if !matches!(path.res, Res::Def(DefKind::TyAlias, _)) => {
+ if let Some(ty) = self.opt_node_type(expr.hir_id)
+ && let ty::Adt(_, substs) = ty.kind()
+ {
+ return Box::new(self.resolved_path_inferred_subst_iter(path, substs));
}
}
hir::ExprKind::MethodCall(segment, ..) => {
@@ -916,6 +931,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
substs,
generics_def_id: def_id,
def_id,
+ have_turbofish: false,
}
};
return Box::new(insertable.into_iter());
@@ -933,6 +949,9 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
substs: SubstsRef<'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()))
+ });
// The last segment of a path often has `Res::Err` and the
// correct `Res` is the one of the whole path.
//
@@ -942,7 +961,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
let generics_def_id = tcx.res_generics_def_id(path.res)?;
let generics = tcx.generics_of(generics_def_id);
if generics.has_impl_trait() {
- None?
+ None?;
}
let insert_span =
path.segments.last().unwrap().ident.span.shrink_to_hi().with_hi(path.span.hi());
@@ -951,6 +970,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
substs,
generics_def_id,
def_id: path.res.def_id(),
+ have_turbofish,
}
};
@@ -970,6 +990,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
substs,
generics_def_id,
def_id: res.def_id(),
+ have_turbofish,
})
})
.chain(last_segment_using_path_data)
@@ -998,7 +1019,13 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
}
let span = tcx.hir().span(segment.hir_id);
let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
- InsertableGenericArgs { insert_span, substs, generics_def_id: def_id, def_id }
+ InsertableGenericArgs {
+ insert_span,
+ substs,
+ generics_def_id: def_id,
+ def_id,
+ have_turbofish: false,
+ }
};
let parent_def_id = generics.parent.unwrap();
@@ -1021,7 +1048,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
}
// There cannot be inference variables in the self type,
// so there's nothing for us to do here.
- Res::SelfTy { .. } => {}
+ Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => {}
_ => warn!(
"unexpected path: def={:?} substs={:?} path={:?}",
def, substs, path,
@@ -1121,7 +1148,13 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
for args in self.expr_inferred_subst_iter(expr) {
debug!(?args);
- let InsertableGenericArgs { insert_span, substs, generics_def_id, def_id } = args;
+ let InsertableGenericArgs {
+ insert_span,
+ substs,
+ generics_def_id,
+ def_id,
+ have_turbofish,
+ } = args;
let generics = tcx.generics_of(generics_def_id);
if let Some(argument_index) = generics
.own_substs(substs)
@@ -1144,6 +1177,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
generics_def_id,
def_id,
generic_args,
+ have_turbofish,
},
});
}
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 3a4320a9a..da0271a34 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
@@ -11,7 +11,7 @@ use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::SubregionOrigin;
use crate::infer::TyCtxt;
-use rustc_errors::AddSubdiagnostic;
+use rustc_errors::AddToDiagnostic;
use rustc_errors::{Diagnostic, ErrorGuaranteed};
use rustc_hir::Ty;
use rustc_middle::ty::Region;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
index 1410e2b63..c5f2a1a3f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
@@ -2,7 +2,9 @@
//! to hold.
use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq};
-use crate::errors::{ImplNote, MismatchedStaticLifetime, TraitSubdiag};
+use crate::errors::{
+ DoesNotOutliveStaticFromImpl, ImplicitStaticLifetimeSubdiag, MismatchedStaticLifetime,
+};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, TypeTrace};
@@ -56,7 +58,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
note_and_explain::SuffixKind::Continues,
);
let mut impl_span = None;
- let mut trait_subdiags = Vec::new();
+ let mut implicit_static_lifetimes = Vec::new();
if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
// If an impl is local, then maybe this isn't what they want. Try to
// be as helpful as possible with implicit lifetimes.
@@ -90,10 +92,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
// Otherwise, point at all implicit static lifetimes
for span in &traits {
- trait_subdiags.push(TraitSubdiag::Note { span: *span });
+ implicit_static_lifetimes
+ .push(ImplicitStaticLifetimeSubdiag::Note { span: *span });
// It would be nice to put this immediately under the above note, but they get
// pushed to the end.
- trait_subdiags.push(TraitSubdiag::Sugg { span: span.shrink_to_hi() });
+ implicit_static_lifetimes
+ .push(ImplicitStaticLifetimeSubdiag::Sugg { span: span.shrink_to_hi() });
}
}
} else {
@@ -105,8 +109,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
cause_span: cause.span,
unmet_lifetime_reqs: multispan_subdiag,
expl,
- impl_note: ImplNote { impl_span },
- trait_subdiags,
+ does_not_outlive_static_from_impl: impl_span
+ .map(|span| DoesNotOutliveStaticFromImpl::Spanned { span })
+ .unwrap_or(DoesNotOutliveStaticFromImpl::Unspanned),
+ implicit_static_lifetimes,
};
let reported = self.tcx().sess.emit_err(err);
Some(reported)
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
index 53d9acf7d..aaf5a7af0 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
@@ -1,6 +1,6 @@
+use crate::infer::error_reporting::TypeErrCtxt;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::lexical_region_resolve::RegionResolutionError::*;
-use crate::infer::InferCtxt;
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::source_map::Span;
@@ -19,34 +19,34 @@ pub use find_anon_type::find_anon_type;
pub use static_impl_trait::{suggest_new_region_bound, HirTraitObjectVisitor, TraitObjectVisitor};
pub use util::find_param_with_region;
-impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
- pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
+impl<'cx, 'tcx> TypeErrCtxt<'cx, 'tcx> {
+ pub fn try_report_nice_region_error(&'cx self, error: &RegionResolutionError<'tcx>) -> bool {
NiceRegionError::new(self, error.clone()).try_report().is_some()
}
}
pub struct NiceRegionError<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ cx: &'cx TypeErrCtxt<'cx, 'tcx>,
error: Option<RegionResolutionError<'tcx>>,
regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>,
}
impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
- pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self {
- Self { infcx, error: Some(error), regions: None }
+ pub fn new(cx: &'cx TypeErrCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self {
+ Self { cx, error: Some(error), regions: None }
}
pub fn new_from_span(
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ cx: &'cx TypeErrCtxt<'cx, 'tcx>,
span: Span,
sub: ty::Region<'tcx>,
sup: ty::Region<'tcx>,
) -> Self {
- Self { infcx, error: None, regions: Some((span, sub, sup)) }
+ Self { cx, error: None, regions: Some((span, sub, sup)) }
}
fn tcx(&self) -> TyCtxt<'tcx> {
- self.infcx.tcx
+ self.cx.tcx
}
pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
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 d4db07512..a58516829 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
@@ -226,12 +226,12 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
false
};
- let expected_trait_ref = self.infcx.resolve_vars_if_possible(ty::TraitRef {
+ let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef {
def_id: trait_def_id,
substs: expected_substs,
});
let actual_trait_ref = self
- .infcx
+ .cx
.resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: actual_substs });
// Search the expected and actual trait references to see (a)
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 ae56bea6f..9bf755d7f 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
@@ -185,8 +185,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
| ObligationCauseCode::BlockTailExpression(hir_id) = cause.code()
{
let parent_id = tcx.hir().get_parent_item(*hir_id);
- let parent_id = tcx.hir().local_def_id_to_hir_id(parent_id);
- if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) {
+ if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) {
let mut span: MultiSpan = fn_decl.output.span().into();
let mut add_label = true;
if let hir::FnRetTy::Return(ty) = fn_decl.output {
@@ -287,8 +286,8 @@ pub fn suggest_new_region_bound(
) {
debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
- let consider = "consider changing the";
- let declare = "to declare that the";
+ let consider = "consider changing";
+ let declare = "to declare that";
let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);
let explicit_static =
arg.map(|arg| format!("explicit `'static` bound to the lifetime of {}", arg));
@@ -306,6 +305,10 @@ pub fn suggest_new_region_bound(
return;
};
+ // Get the identity type for this RPIT
+ let did = item_id.owner_id.to_def_id();
+ let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did));
+
if let Some(span) = opaque
.bounds
.iter()
@@ -322,7 +325,7 @@ pub fn suggest_new_region_bound(
if let Some(explicit_static) = &explicit_static {
err.span_suggestion_verbose(
span,
- &format!("{} `impl Trait`'s {}", consider, explicit_static),
+ &format!("{consider} `{ty}`'s {explicit_static}"),
&lifetime_name,
Applicability::MaybeIncorrect,
);
@@ -352,12 +355,7 @@ pub fn suggest_new_region_bound(
} else {
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
- &format!(
- "{declare} `impl Trait` {captures}, {explicit}",
- declare = declare,
- captures = captures,
- explicit = explicit,
- ),
+ &format!("{declare} `{ty}` {captures}, {explicit}",),
&plus_lt,
Applicability::MaybeIncorrect,
);
@@ -368,7 +366,7 @@ pub fn suggest_new_region_bound(
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
&format!(
- "{declare} trait object {captures}, {explicit}",
+ "{declare} the trait object {captures}, {explicit}",
declare = declare,
captures = captures,
explicit = explicit,
@@ -385,7 +383,7 @@ pub fn suggest_new_region_bound(
if let Some(explicit_static) = &explicit_static {
err.span_suggestion_verbose(
lt.span,
- &format!("{} trait object's {}", consider, explicit_static),
+ &format!("{} the trait object's {}", consider, explicit_static),
&lifetime_name,
Applicability::MaybeIncorrect,
);
@@ -415,7 +413,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let tcx = self.tcx();
match tcx.hir().get_if_local(def_id) {
Some(Node::ImplItem(impl_item)) => {
- match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id())) {
+ match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
+ {
Some(Node::Item(Item {
kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
..
@@ -425,7 +424,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
}
Some(Node::TraitItem(trait_item)) => {
let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
- match tcx.hir().find_by_def_id(trait_did) {
+ match tcx.hir().find_by_def_id(trait_did.def_id) {
Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
// The method being called is defined in the `trait`, but the `'static`
// obligation comes from the `impl`. Find that `impl` so that we can point
@@ -486,7 +485,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
tcx,
ctxt.param_env,
ctxt.assoc_item.def_id,
- self.infcx.resolve_vars_if_possible(ctxt.substs),
+ self.cx.resolve_vars_if_possible(ctxt.substs),
) else {
return false;
};
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 a6a39d062..5d536e982 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
@@ -84,12 +84,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
let expected = self
- .infcx
+ .cx
.extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
.name;
let found_highlight = HighlightBuilder::build(self.tcx(), found);
let found =
- self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
+ self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
err.span_label(sp, &format!("found `{}`", found));
err.span_label(trait_sp, &format!("expected `{}`", expected));
@@ -156,7 +156,8 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
[segment]
if matches!(
segment.res,
- Res::SelfTy { trait_: _, alias_to: _ }
+ Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. }
| Res::Def(hir::def::DefKind::TyParam, _)
) =>
{
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index 3e9d491af..f1461d701 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -130,7 +130,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let ret_ty = fn_ty.fn_sig(self.tcx()).output();
let span = hir_sig.decl.output.span();
let future_output = if hir_sig.header.is_async() {
- ret_ty.map_bound(|ty| self.infcx.get_impl_future_output_ty(ty)).transpose()
+ ret_ty.map_bound(|ty| self.cx.get_impl_future_output_ty(ty)).transpose()
} else {
None
};
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index adaa47c01..41b115f33 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -1,8 +1,8 @@
use crate::errors::RegionOriginNote;
-use crate::infer::error_reporting::note_and_explain_region;
-use crate::infer::{self, InferCtxt, SubregionOrigin};
+use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
+use crate::infer::{self, SubregionOrigin};
use rustc_errors::{
- fluent, struct_span_err, AddSubdiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+ fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
};
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::TypeError;
@@ -10,7 +10,7 @@ use rustc_middle::ty::{self, Region};
use super::ObligationCauseAsDiagArg;
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) {
match *origin {
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
@@ -19,26 +19,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
expected_found: self.values_str(trace.values),
}
.add_to_diagnostic(err),
- infer::Reborrow(span) => RegionOriginNote::Plain { span, msg: fluent::infer::reborrow }
- .add_to_diagnostic(err),
+ infer::Reborrow(span) => {
+ RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
+ }
infer::ReborrowUpvar(span, ref upvar_id) => {
let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
RegionOriginNote::WithName {
span,
- msg: fluent::infer::reborrow,
+ msg: fluent::infer_reborrow,
name: &var_name.to_string(),
continues: false,
}
.add_to_diagnostic(err);
}
infer::RelateObjectBound(span) => {
- RegionOriginNote::Plain { span, msg: fluent::infer::relate_object_bound }
+ RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
.add_to_diagnostic(err);
}
infer::DataBorrowed(ty, span) => {
RegionOriginNote::WithName {
span,
- msg: fluent::infer::data_borrowed,
+ msg: fluent::infer_data_borrowed,
name: &self.ty_to_string(ty),
continues: false,
}
@@ -47,7 +48,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
infer::ReferenceOutlivesReferent(ty, span) => {
RegionOriginNote::WithName {
span,
- msg: fluent::infer::reference_outlives_referent,
+ msg: fluent::infer_reference_outlives_referent,
name: &self.ty_to_string(ty),
continues: false,
}
@@ -56,22 +57,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
infer::RelateParamBound(span, ty, opt_span) => {
RegionOriginNote::WithName {
span,
- msg: fluent::infer::relate_param_bound,
+ msg: fluent::infer_relate_param_bound,
name: &self.ty_to_string(ty),
continues: opt_span.is_some(),
}
.add_to_diagnostic(err);
if let Some(span) = opt_span {
- RegionOriginNote::Plain { span, msg: fluent::infer::relate_param_bound_2 }
+ RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
.add_to_diagnostic(err);
}
}
infer::RelateRegionParamBound(span) => {
- RegionOriginNote::Plain { span, msg: fluent::infer::relate_region_param_bound }
+ RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
.add_to_diagnostic(err);
}
infer::CompareImplItemObligation { span, .. } => {
- RegionOriginNote::Plain { span, msg: fluent::infer::compare_impl_item_obligation }
+ RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
.add_to_diagnostic(err);
}
infer::CheckAssociatedTypeBounds { ref parent, .. } => {
@@ -80,7 +81,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
infer::AscribeUserTypeProvePredicate(span) => {
RegionOriginNote::Plain {
span,
- msg: fluent::infer::ascribe_user_type_prove_predicate,
+ msg: fluent::infer_ascribe_user_type_prove_predicate,
}
.add_to_diagnostic(err);
}
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index fee15afc7..ff5d1a05a 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -38,7 +38,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVi
use std::collections::hash_map::Entry;
pub struct TypeFreshener<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
ty_freshen_count: u32,
const_freshen_count: u32,
ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
@@ -47,7 +47,7 @@ pub struct TypeFreshener<'a, 'tcx> {
}
impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
- pub fn new(infcx: &'a InferCtxt<'a, 'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> {
+ pub fn new(infcx: &'a InferCtxt<'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> {
TypeFreshener {
infcx,
ty_freshen_count: 0,
diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs
index 2f0eadce6..6dd6c4e1f 100644
--- a/compiler/rustc_infer/src/infer/fudge.rs
+++ b/compiler/rustc_infer/src/infer/fudge.rs
@@ -43,7 +43,7 @@ struct VariableLengths {
region_constraints_len: usize,
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
fn variable_lengths(&self) -> VariableLengths {
let mut inner = self.inner.borrow_mut();
VariableLengths {
@@ -167,7 +167,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
pub struct InferenceFudger<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
type_vars: (Range<TyVid>, Vec<TypeVariableOrigin>),
int_vars: Range<IntVid>,
float_vars: Range<FloatVid>,
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 1570a08f3..6ffefcb7a 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -113,7 +113,7 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
}
impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, 'tcx> {
- fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'tcx> {
+ fn infcx(&self) -> &'infcx InferCtxt<'tcx> {
self.fields.infcx
}
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index 0ce271c0e..28c87a115 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -59,7 +59,7 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
}
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Replaces all bound variables (lifetimes, types, and constants) bound by
/// `binder` with placeholder variables in a new universe. This means that the
/// new placeholders can only be named by inference variables created after
@@ -114,7 +114,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn leak_check(
&self,
overly_polymorphic: bool,
- snapshot: &CombinedSnapshot<'_, 'tcx>,
+ snapshot: &CombinedSnapshot<'tcx>,
) -> RelateResult<'tcx, ()> {
// If the user gave `-Zno-leak-check`, or we have been
// configured to skip the leak check, then skip the leak check
diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs
index 1e3293efa..eba65361a 100644
--- a/compiler/rustc_infer/src/infer/lattice.rs
+++ b/compiler/rustc_infer/src/infer/lattice.rs
@@ -31,7 +31,7 @@ use rustc_middle::ty::{self, Ty};
/// GLB moves "down" the lattice (to smaller values); LUB moves
/// "up" the lattice (to bigger values).
pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
- fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>;
+ fn infcx(&self) -> &'f InferCtxt<'tcx>;
fn cause(&self) -> &ObligationCause<'tcx>;
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index 9f96d52c8..d6e56fcb7 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -119,7 +119,7 @@ impl<'tcx> ConstEquateRelation<'tcx> for Lub<'_, '_, 'tcx> {
}
impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, 'tcx> {
- fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'tcx> {
+ fn infcx(&self) -> &'infcx InferCtxt<'tcx> {
self.fields.infcx
}
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 3abed1221..ffb020398 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -35,10 +35,11 @@ use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid};
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
-use std::cell::{Cell, Ref, RefCell};
+use std::cell::{Cell, RefCell};
use std::fmt;
use self::combine::CombineFields;
+use self::error_reporting::TypeErrCtxt;
use self::free_regions::RegionRelations;
use self::lexical_region_resolve::LexicalRegionResolutions;
use self::outlives::env::OutlivesEnvironment;
@@ -252,7 +253,7 @@ pub enum DefiningAnchor {
Error,
}
-pub struct InferCtxt<'a, 'tcx> {
+pub struct InferCtxt<'tcx> {
pub tcx: TyCtxt<'tcx>,
/// The `DefId` of the item in whose context we are performing inference or typeck.
@@ -272,12 +273,6 @@ pub struct InferCtxt<'a, 'tcx> {
/// solving is left to borrowck instead.
pub considering_regions: bool,
- /// During type-checking/inference of a body, `in_progress_typeck_results`
- /// contains a reference to the typeck results being built up, which are
- /// used for reading closure kinds/signatures as they are inferred,
- /// and for error reporting logic to read arbitrary node types.
- pub in_progress_typeck_results: Option<&'a RefCell<ty::TypeckResults<'tcx>>>,
-
pub inner: RefCell<InferCtxtInner<'tcx>>,
/// If set, this flag causes us to skip the 'leak check' during
@@ -340,7 +335,7 @@ pub struct InferCtxt<'a, 'tcx> {
universe: Cell<ty::UniverseIndex>,
normalize_fn_sig_for_diagnostic:
- Option<Lrc<dyn Fn(&InferCtxt<'_, 'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
+ Option<Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
}
/// See the `error_reporting` module for more details.
@@ -551,16 +546,13 @@ impl<'tcx> fmt::Display for FixupError<'tcx> {
}
}
-/// A temporary returned by `tcx.infer_ctxt()`. This is necessary
-/// for multiple `InferCtxt` to share the same `in_progress_typeck_results`
-/// without using `Rc` or something similar.
+/// Used to configure inference contexts before their creation
pub struct InferCtxtBuilder<'tcx> {
tcx: TyCtxt<'tcx>,
defining_use_anchor: DefiningAnchor,
considering_regions: bool,
- fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
normalize_fn_sig_for_diagnostic:
- Option<Lrc<dyn Fn(&InferCtxt<'_, 'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
+ Option<Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
}
pub trait TyCtxtInferExt<'tcx> {
@@ -573,26 +565,17 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
tcx: self,
defining_use_anchor: DefiningAnchor::Error,
considering_regions: true,
- fresh_typeck_results: None,
normalize_fn_sig_for_diagnostic: None,
}
}
}
impl<'tcx> InferCtxtBuilder<'tcx> {
- /// Used only by `rustc_typeck` during body type-checking/inference,
- /// will initialize `in_progress_typeck_results` with fresh `TypeckResults`.
- /// Will also change the scope for opaque type defining use checks to the given owner.
- pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: LocalDefId) -> Self {
- self.fresh_typeck_results = Some(RefCell::new(ty::TypeckResults::new(table_owner)));
- self.with_opaque_type_inference(DefiningAnchor::Bind(table_owner))
- }
-
/// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
/// you need to call this function. Otherwise the opaque type will be treated opaquely.
///
/// It is only meant to be called in two places, for typeck
- /// (via `with_fresh_in_progress_typeck_results`) and for the inference context used
+ /// (via `Inherited::build`) and for the inference context used
/// in mir borrowck.
pub fn with_opaque_type_inference(mut self, defining_use_anchor: DefiningAnchor) -> Self {
self.defining_use_anchor = defining_use_anchor;
@@ -606,7 +589,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
pub fn with_normalize_fn_sig_for_diagnostic(
mut self,
- fun: Lrc<dyn Fn(&InferCtxt<'_, 'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>,
+ fun: Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>,
) -> Self {
self.normalize_fn_sig_for_diagnostic = Some(fun);
self
@@ -619,36 +602,30 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
/// `V` and a substitution `S`. This substitution `S` maps from
/// the bound values in `C` to their instantiated values in `V`
/// (in other words, `S(C) = V`).
- pub fn enter_with_canonical<T, R>(
+ pub fn build_with_canonical<T>(
&mut self,
span: Span,
canonical: &Canonical<'tcx, T>,
- f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>, T, CanonicalVarValues<'tcx>) -> R,
- ) -> R
+ ) -> (InferCtxt<'tcx>, T, CanonicalVarValues<'tcx>)
where
T: TypeFoldable<'tcx>,
{
- self.enter(|infcx| {
- let (value, subst) =
- infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
- f(infcx, value, subst)
- })
+ let infcx = self.build();
+ let (value, subst) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
+ (infcx, value, subst)
}
- pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
+ pub fn build(&mut self) -> InferCtxt<'tcx> {
let InferCtxtBuilder {
tcx,
defining_use_anchor,
considering_regions,
- ref fresh_typeck_results,
ref normalize_fn_sig_for_diagnostic,
} = *self;
- let in_progress_typeck_results = fresh_typeck_results.as_ref();
- f(InferCtxt {
+ InferCtxt {
tcx,
defining_use_anchor,
considering_regions,
- in_progress_typeck_results,
inner: RefCell::new(InferCtxtInner::new()),
lexical_region_resolutions: RefCell::new(None),
selection_cache: Default::default(),
@@ -663,7 +640,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
normalize_fn_sig_for_diagnostic: normalize_fn_sig_for_diagnostic
.as_ref()
.map(|f| f.clone()),
- })
+ }
}
}
@@ -675,7 +652,7 @@ impl<'tcx, T> InferOk<'tcx, T> {
/// Extracts `value`, registering any obligations into `fulfill_cx`.
pub fn into_value_registering_obligations(
self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
fulfill_cx: &mut dyn TraitEngine<'tcx>,
) -> T {
let InferOk { value, obligations } = self;
@@ -691,29 +668,34 @@ impl<'tcx> InferOk<'tcx, ()> {
}
#[must_use = "once you start a snapshot, you should always consume it"]
-pub struct CombinedSnapshot<'a, 'tcx> {
+pub struct CombinedSnapshot<'tcx> {
undo_snapshot: Snapshot<'tcx>,
region_constraints_snapshot: RegionSnapshot,
universe: ty::UniverseIndex,
was_in_snapshot: bool,
- _in_progress_typeck_results: Option<Ref<'a, ty::TypeckResults<'tcx>>>,
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
+ /// Creates a `TypeErrCtxt` for emitting various inference errors.
+ /// During typeck, use `FnCtxt::infer_err` instead.
+ pub fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> {
+ TypeErrCtxt { infcx: self, typeck_results: None }
+ }
+
/// calls `tcx.try_unify_abstract_consts` after
/// canonicalizing the consts.
#[instrument(skip(self), level = "debug")]
pub fn try_unify_abstract_consts(
&self,
- a: ty::Unevaluated<'tcx, ()>,
- b: ty::Unevaluated<'tcx, ()>,
+ a: ty::UnevaluatedConst<'tcx>,
+ b: ty::UnevaluatedConst<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
// Reject any attempt to unify two unevaluated constants that contain inference
// variables, since inference variables in queries lead to ICEs.
- if a.substs.has_infer_types_or_consts()
- || b.substs.has_infer_types_or_consts()
- || param_env.has_infer_types_or_consts()
+ if a.substs.has_non_region_infer()
+ || b.substs.has_non_region_infer()
+ || param_env.has_non_region_infer()
{
debug!("a or b or param_env contain infer vars in its substs -> cannot unify");
return false;
@@ -738,7 +720,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// if this is not a type variable.
///
/// No attempt is made to resolve `ty`.
- pub fn type_var_origin(&'a self, ty: Ty<'tcx>) -> Option<TypeVariableOrigin> {
+ pub fn type_var_origin(&self, ty: Ty<'tcx>) -> Option<TypeVariableOrigin> {
match *ty.kind() {
ty::Infer(ty::TyVar(vid)) => {
Some(*self.inner.borrow_mut().type_variables().var_origin(vid))
@@ -779,7 +761,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
vars
}
- fn combine_fields(
+ fn combine_fields<'a>(
&'a self,
trace: TypeTrace<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -821,7 +803,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
result
}
- fn start_snapshot(&self) -> CombinedSnapshot<'a, 'tcx> {
+ fn start_snapshot(&self) -> CombinedSnapshot<'tcx> {
debug!("start_snapshot()");
let in_snapshot = self.in_snapshot.replace(true);
@@ -833,22 +815,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(),
universe: self.universe(),
was_in_snapshot: in_snapshot,
- // Borrow typeck results "in progress" (i.e., during typeck)
- // to ban writes from within a snapshot to them.
- _in_progress_typeck_results: self
- .in_progress_typeck_results
- .map(|typeck_results| typeck_results.borrow()),
}
}
#[instrument(skip(self, snapshot), level = "debug")]
- fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) {
+ fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'tcx>) {
let CombinedSnapshot {
undo_snapshot,
region_constraints_snapshot,
universe,
was_in_snapshot,
- _in_progress_typeck_results,
} = snapshot;
self.in_snapshot.set(was_in_snapshot);
@@ -860,13 +836,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
#[instrument(skip(self, snapshot), level = "debug")]
- fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
+ fn commit_from(&self, snapshot: CombinedSnapshot<'tcx>) {
let CombinedSnapshot {
undo_snapshot,
region_constraints_snapshot: _,
universe: _,
was_in_snapshot,
- _in_progress_typeck_results,
} = snapshot;
self.in_snapshot.set(was_in_snapshot);
@@ -878,7 +853,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
#[instrument(skip(self, f), level = "debug")]
pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
where
- F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result<T, E>,
+ F: FnOnce(&CombinedSnapshot<'tcx>) -> Result<T, E>,
{
let snapshot = self.start_snapshot();
let r = f(&snapshot);
@@ -898,7 +873,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
#[instrument(skip(self, f), level = "debug")]
pub fn probe<R, F>(&self, f: F) -> R
where
- F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
+ F: FnOnce(&CombinedSnapshot<'tcx>) -> R,
{
let snapshot = self.start_snapshot();
let r = f(&snapshot);
@@ -910,7 +885,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
#[instrument(skip(self, f), level = "debug")]
pub fn probe_maybe_skip_leak_check<R, F>(&self, should_skip: bool, f: F) -> R
where
- F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
+ F: FnOnce(&CombinedSnapshot<'tcx>) -> R,
{
let snapshot = self.start_snapshot();
let was_skip_leak_check = self.skip_leak_check.get();
@@ -930,7 +905,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders
pub fn region_constraints_added_in_snapshot(
&self,
- snapshot: &CombinedSnapshot<'a, 'tcx>,
+ snapshot: &CombinedSnapshot<'tcx>,
) -> Option<bool> {
self.inner
.borrow_mut()
@@ -938,7 +913,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.region_constraints_added_in_snapshot(&snapshot.undo_snapshot)
}
- pub fn opaque_types_added_in_snapshot(&self, snapshot: &CombinedSnapshot<'a, 'tcx>) -> bool {
+ pub fn opaque_types_added_in_snapshot(&self, snapshot: &CombinedSnapshot<'tcx>) -> bool {
self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot)
}
@@ -1175,8 +1150,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// Return the universe that the region `r` was created in. For
/// most regions (e.g., `'static`, named regions from the user,
/// etc) this is the root universe U0. For inference variables or
- /// placeholders, however, it will return the universe which which
- /// they are associated.
+ /// placeholders, however, it will return the universe which they
+ /// are associated.
pub fn universe_of_region(&self, r: ty::Region<'tcx>) -> ty::UniverseIndex {
self.inner.borrow_mut().unwrap_region_constraints().universe(r)
}
@@ -1308,7 +1283,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
assert!(old_value.is_none());
}
- /// Process the region constraints and return any any errors that
+ /// Process the region constraints and return any errors that
/// result. After this, no more unification operations should be
/// done -- or the compiler will panic -- but it is legal to use
/// `resolve_vars_if_possible` as well as `fully_resolve`.
@@ -1342,32 +1317,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
errors
}
-
- /// Process the region constraints and report any errors that
- /// result. After this, no more unification operations should be
- /// done -- or the compiler will panic -- but it is legal to use
- /// `resolve_vars_if_possible` as well as `fully_resolve`.
- ///
- /// Make sure to call [`InferCtxt::process_registered_region_obligations`]
- /// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`]
- /// to do both of these operations together.
- pub fn resolve_regions_and_report_errors(
- &self,
- generic_param_scope: LocalDefId,
- outlives_env: &OutlivesEnvironment<'tcx>,
- ) {
- let errors = self.resolve_regions(outlives_env);
-
- if !self.is_tainted_by_errors() {
- // As a heuristic, just skip reporting region errors
- // altogether if other errors have been reported while
- // this infcx was in use. This is totally hokey but
- // otherwise we have a hard time separating legit region
- // errors from silly ones.
- self.report_region_errors(generic_param_scope, &errors);
- }
- }
-
/// Obtains (and clears) the current set of region
/// constraints. The inference context is still usable: further
/// unifications will simply add new constraints.
@@ -1520,60 +1469,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
* except during the writeback phase.
*/
- resolve::fully_resolve(self, value)
- }
-
- // [Note-Type-error-reporting]
- // An invariant is that anytime the expected or actual type is Error (the special
- // error type, meaning that an error occurred when typechecking this expression),
- // this is a derived error. The error cascaded from another error (that was already
- // reported), so it's not useful to display it to the user.
- // The following methods implement this logic.
- // They check if either the actual or expected type is Error, and don't print the error
- // in this case. The typechecker should only ever report type errors involving mismatched
- // types using one of these methods, and should not call span_err directly for such
- // errors.
-
- pub fn type_error_struct_with_diag<M>(
- &self,
- sp: Span,
- mk_diag: M,
- actual_ty: Ty<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
- where
- M: FnOnce(String) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>,
- {
- let actual_ty = self.resolve_vars_if_possible(actual_ty);
- debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
-
- let mut err = mk_diag(self.ty_to_string(actual_ty));
-
- // Don't report an error if actual type is `Error`.
- if actual_ty.references_error() {
- err.downgrade_to_delayed_bug();
- }
-
- err
- }
-
- pub fn report_mismatched_types(
- &self,
- cause: &ObligationCause<'tcx>,
- expected: Ty<'tcx>,
- actual: Ty<'tcx>,
- err: TypeError<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err)
- }
-
- pub fn report_mismatched_consts(
- &self,
- cause: &ObligationCause<'tcx>,
- expected: ty::Const<'tcx>,
- actual: ty::Const<'tcx>,
- err: TypeError<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err)
+ let value = resolve::fully_resolve(self, value);
+ assert!(
+ value.as_ref().map_or(true, |value| !value.needs_infer()),
+ "`{value:?}` is not fully resolved"
+ );
+ value
}
pub fn replace_bound_vars_with_fresh_vars<T>(
@@ -1590,7 +1491,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
struct ToFreshVars<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
span: Span,
lbrct: LateBoundRegionConversionTime,
map: FxHashMap<ty::BoundVar, ty::GenericArg<'tcx>>,
@@ -1690,7 +1591,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn try_const_eval_resolve(
&self,
param_env: ty::ParamEnv<'tcx>,
- unevaluated: ty::Unevaluated<'tcx, ()>,
+ unevaluated: ty::UnevaluatedConst<'tcx>,
ty: Ty<'tcx>,
span: Option<Span>,
) -> Result<ty::Const<'tcx>, ErrorHandled> {
@@ -1725,7 +1626,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn const_eval_resolve(
&self,
mut param_env: ty::ParamEnv<'tcx>,
- unevaluated: ty::Unevaluated<'tcx, ()>,
+ unevaluated: ty::UnevaluatedConst<'tcx>,
span: Option<Span>,
) -> EvalToValTreeResult<'tcx> {
let mut substs = self.resolve_vars_if_possible(unevaluated.substs);
@@ -1733,7 +1634,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// Postpone the evaluation of constants whose substs depend on inference
// variables
- if substs.has_infer_types_or_consts() {
+ if substs.has_non_region_infer() {
let ac = AbstractConst::new(self.tcx, unevaluated);
match ac {
Ok(None) => {
@@ -1756,8 +1657,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
debug!(?param_env_erased);
debug!(?substs_erased);
- let unevaluated =
- ty::Unevaluated { def: unevaluated.def, substs: substs_erased, promoted: () };
+ let unevaluated = ty::UnevaluatedConst { def: unevaluated.def, substs: substs_erased };
// The return value is the evaluated value which doesn't contain any reference to inference
// variables, thus we don't need to substitute back the original values.
@@ -1816,6 +1716,86 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
+ /// Process the region constraints and report any errors that
+ /// result. After this, no more unification operations should be
+ /// done -- or the compiler will panic -- but it is legal to use
+ /// `resolve_vars_if_possible` as well as `fully_resolve`.
+ ///
+ /// Make sure to call [`InferCtxt::process_registered_region_obligations`]
+ /// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`]
+ /// to do both of these operations together.
+ pub fn resolve_regions_and_report_errors(
+ &self,
+ generic_param_scope: LocalDefId,
+ outlives_env: &OutlivesEnvironment<'tcx>,
+ ) {
+ let errors = self.resolve_regions(outlives_env);
+
+ if !self.is_tainted_by_errors() {
+ // As a heuristic, just skip reporting region errors
+ // altogether if other errors have been reported while
+ // this infcx was in use. This is totally hokey but
+ // otherwise we have a hard time separating legit region
+ // errors from silly ones.
+ self.report_region_errors(generic_param_scope, &errors);
+ }
+ }
+
+ // [Note-Type-error-reporting]
+ // An invariant is that anytime the expected or actual type is Error (the special
+ // error type, meaning that an error occurred when typechecking this expression),
+ // this is a derived error. The error cascaded from another error (that was already
+ // reported), so it's not useful to display it to the user.
+ // The following methods implement this logic.
+ // They check if either the actual or expected type is Error, and don't print the error
+ // in this case. The typechecker should only ever report type errors involving mismatched
+ // types using one of these methods, and should not call span_err directly for such
+ // errors.
+
+ pub fn type_error_struct_with_diag<M>(
+ &self,
+ sp: Span,
+ mk_diag: M,
+ actual_ty: Ty<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
+ where
+ M: FnOnce(String) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ {
+ let actual_ty = self.resolve_vars_if_possible(actual_ty);
+ debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
+
+ let mut err = mk_diag(self.ty_to_string(actual_ty));
+
+ // Don't report an error if actual type is `Error`.
+ if actual_ty.references_error() {
+ err.downgrade_to_delayed_bug();
+ }
+
+ err
+ }
+
+ pub fn report_mismatched_types(
+ &self,
+ cause: &ObligationCause<'tcx>,
+ expected: Ty<'tcx>,
+ actual: Ty<'tcx>,
+ err: TypeError<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err)
+ }
+
+ pub fn report_mismatched_consts(
+ &self,
+ cause: &ObligationCause<'tcx>,
+ expected: ty::Const<'tcx>,
+ actual: ty::Const<'tcx>,
+ err: TypeError<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err)
+ }
+}
+
/// Helper for `ty_or_const_infer_var_changed` (see comment on that), currently
/// used only for `traits::fulfill`'s list of `stalled_on` inference variables.
#[derive(Copy, Clone, Debug)]
@@ -1885,7 +1865,7 @@ impl<'tcx> TypeFolder<'tcx> for InferenceLiteralEraser<'tcx> {
}
struct ShallowResolver<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
@@ -2072,21 +2052,17 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>(
) -> SubstsRef<'tcx> {
tcx.mk_substs(substs.iter().enumerate().map(|(idx, arg)| {
match arg.unpack() {
- GenericArgKind::Type(_)
- if arg.has_param_types_or_consts() || arg.has_infer_types_or_consts() =>
- {
+ GenericArgKind::Type(_) if arg.has_non_region_param() || arg.has_non_region_infer() => {
tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
universe: ty::UniverseIndex::ROOT,
name: ty::BoundVar::from_usize(idx),
}))
.into()
}
- GenericArgKind::Const(ct)
- if ct.has_infer_types_or_consts() || ct.has_param_types_or_consts() =>
- {
+ GenericArgKind::Const(ct) if ct.has_non_region_infer() || ct.has_non_region_param() => {
let ty = ct.ty();
// If the type references param or infer, replace that too...
- if ty.has_param_types_or_consts() || ty.has_infer_types_or_consts() {
+ if ty.has_non_region_param() || ty.has_non_region_infer() {
bug!("const `{ct}`'s type should not reference params or types");
}
tcx.mk_const(ty::ConstS {
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 00fc442d3..600f94f09 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -25,7 +25,9 @@ use crate::infer::combine::ConstEquateRelation;
use crate::infer::InferCtxt;
use crate::infer::{ConstVarValue, ConstVariableValue};
use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::traits::PredicateObligation;
use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
@@ -44,7 +46,7 @@ pub struct TypeRelating<'me, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
- infcx: &'me InferCtxt<'me, 'tcx>,
+ infcx: &'me InferCtxt<'tcx>,
/// Callback to use when we deduce an outlives relationship.
delegate: D,
@@ -91,11 +93,9 @@ pub trait TypeRelatingDelegate<'tcx> {
);
fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
- fn register_opaque_type(
+ fn register_opaque_type_obligations(
&mut self,
- a: Ty<'tcx>,
- b: Ty<'tcx>,
- a_is_expected: bool,
+ obligations: Vec<PredicateObligation<'tcx>>,
) -> Result<(), TypeError<'tcx>>;
/// Creates a new universe index. Used when instantiating placeholders.
@@ -149,11 +149,7 @@ impl<'me, 'tcx, D> TypeRelating<'me, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
- pub fn new(
- infcx: &'me InferCtxt<'me, 'tcx>,
- delegate: D,
- ambient_variance: ty::Variance,
- ) -> Self {
+ pub fn new(infcx: &'me InferCtxt<'tcx>, delegate: D, ambient_variance: ty::Variance) -> Self {
Self {
infcx,
delegate,
@@ -357,7 +353,7 @@ where
// In NLL, we don't have type inference variables
// floating around, so we can do this rather imprecise
// variant of the occurs-check.
- assert!(!generalized_ty.has_infer_types_or_consts());
+ assert!(!generalized_ty.has_non_region_infer());
}
self.infcx.inner.borrow_mut().type_variables().instantiate(vid, generalized_ty);
@@ -418,7 +414,12 @@ where
(_, &ty::Opaque(..)) => (generalize(a, true)?, b),
_ => unreachable!(),
};
- self.delegate.register_opaque_type(a, b, true)?;
+ let cause = ObligationCause::dummy_with_span(self.delegate.span());
+ let obligations = self
+ .infcx
+ .handle_opaque_type(a, b, true, &cause, self.delegate.param_env())?
+ .obligations;
+ self.delegate.register_opaque_type_obligations(obligations)?;
trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
Ok(a)
}
@@ -867,7 +868,7 @@ struct TypeGeneralizer<'me, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
- infcx: &'me InferCtxt<'me, 'tcx>,
+ infcx: &'me InferCtxt<'tcx>,
delegate: &'me mut D,
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 8c9ddf866..a982f11f7 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -1,14 +1,16 @@
use crate::errors::OpaqueHiddenTypeDiag;
use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
use crate::traits;
+use hir::def::DefKind;
use hir::def_id::{DefId, LocalDefId};
use hir::{HirId, OpaqueTyOrigin};
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir;
use rustc_middle::traits::ObligationCause;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BottomUpFolder;
-use rustc_middle::ty::subst::{GenericArgKind, Subst};
+use rustc_middle::ty::GenericArgKind;
use rustc_middle::ty::{
self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
TypeVisitable, TypeVisitor,
@@ -40,7 +42,7 @@ pub struct OpaqueTypeDecl<'tcx> {
pub origin: hir::OpaqueTyOrigin,
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// This is a backwards compatibility hack to prevent breaking changes from
/// lazy TAIT around RPIT handling.
pub fn replace_opaque_types_with_inference_vars<T: TypeFoldable<'tcx>>(
@@ -101,7 +103,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
return Ok(InferOk { value: (), obligations: vec![] });
}
let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
- let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
+ let process = |a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected| match *a.kind() {
ty::Opaque(def_id, substs) if def_id.is_local() => {
let def_id = def_id.expect_local();
let origin = match self.defining_use_anchor {
@@ -167,25 +169,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
param_env,
b,
origin,
+ a_is_expected,
))
}
_ => None,
};
- if let Some(res) = process(a, b) {
+ if let Some(res) = process(a, b, true) {
res
- } else if let Some(res) = process(b, a) {
+ } else if let Some(res) = process(b, a, false) {
res
} else {
- // Rerun equality check, but this time error out due to
- // different types.
- match self.at(cause, param_env).define_opaque_types(false).eq(a, b) {
- Ok(_) => span_bug!(
- cause.span,
- "opaque types are never equal to anything but themselves: {:#?}",
- (a.kind(), b.kind())
- ),
- Err(e) => Err(e),
- }
+ let (a, b) = self.resolve_vars_if_possible((a, b));
+ Err(TypeError::Sorts(ExpectedFound::new(true, a, b)))
}
}
@@ -518,15 +513,16 @@ impl UseKind {
}
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
#[instrument(skip(self), level = "debug")]
- pub fn register_hidden_type(
+ fn register_hidden_type(
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
origin: hir::OpaqueTyOrigin,
+ a_is_expected: bool,
) -> InferResult<'tcx, ()> {
let tcx = self.tcx;
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
@@ -545,21 +541,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin,
);
if let Some(prev) = prev {
- obligations = self.at(&cause, param_env).eq(prev, hidden_ty)?.obligations;
+ obligations =
+ self.at(&cause, param_env).eq_exp(a_is_expected, prev, hidden_ty)?.obligations;
}
let item_bounds = tcx.bound_explicit_item_bounds(def_id.to_def_id());
- for predicate in item_bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
- debug!(?predicate);
- let predicate = predicate.subst(tcx, substs);
-
+ for (predicate, _) in item_bounds.subst_iter_copied(tcx, substs) {
let predicate = predicate.fold_with(&mut BottomUpFolder {
tcx,
ty_op: |ty| match *ty.kind() {
// We can't normalize associated types from `rustc_infer`,
// but we can eagerly register inference variables for them.
- ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => {
+ // FIXME(RPITIT): Don't replace RPITITs with inference vars.
+ ty::Projection(projection_ty)
+ if !projection_ty.has_escaping_bound_vars()
+ && tcx.def_kind(projection_ty.item_def_id)
+ != DefKind::ImplTraitPlaceholder =>
+ {
self.infer_projection(
param_env,
projection_ty,
@@ -575,6 +574,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
{
hidden_ty
}
+ // FIXME(RPITIT): This can go away when we move to associated types
+ ty::Projection(proj)
+ if def_id.to_def_id() == proj.item_def_id && substs == proj.substs =>
+ {
+ hidden_ty
+ }
_ => ty,
},
lt_op: |lt| lt,
@@ -623,7 +628,7 @@ fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hi
let scope = tcx.hir().get_defining_scope(opaque_hir_id);
// We walk up the node tree until we hit the root or the scope of the opaque type.
while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
- hir_id = tcx.hir().local_def_id_to_hir_id(tcx.hir().get_parent_item(hir_id));
+ hir_id = tcx.hir().get_parent_item(hir_id).into();
}
// Syntactically, we are allowed to define the concrete type if:
let res = hir_id == scope;
diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs
index b2d7f4a66..14ee9f051 100644
--- a/compiler/rustc_infer/src/infer/outlives/components.rs
+++ b/compiler/rustc_infer/src/infer/outlives/components.rs
@@ -3,8 +3,9 @@
// RFC for reference.
use rustc_data_structures::sso::SsoHashSet;
+use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, SubstsRef, Ty, TyCtxt, TypeVisitable};
use smallvec::{smallvec, SmallVec};
#[derive(Debug)]
@@ -45,6 +46,8 @@ pub enum Component<'tcx> {
// them. This gives us room to improve the regionck reasoning in
// the future without breaking backwards compat.
EscapingProjection(Vec<Component<'tcx>>),
+
+ Opaque(DefId, SubstsRef<'tcx>),
}
/// Push onto `out` all the things that must outlive `'a` for the condition
@@ -120,6 +123,17 @@ fn compute_components<'tcx>(
out.push(Component::Param(p));
}
+ // Ignore lifetimes found in opaque types. Opaque types can
+ // have lifetimes in their substs which their hidden type doesn't
+ // actually use. If we inferred that an opaque type is outlived by
+ // its parameter lifetimes, then we could prove that any lifetime
+ // outlives any other lifetime, which is unsound.
+ // See https://github.com/rust-lang/rust/issues/84305 for
+ // more details.
+ ty::Opaque(def_id, substs) => {
+ out.push(Component::Opaque(def_id, substs));
+ },
+
// For projections, we prefer to generate an obligation like
// `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
// regionck more ways to prove that it holds. However,
@@ -168,7 +182,6 @@ fn compute_components<'tcx>(
ty::Float(..) | // OutlivesScalar
ty::Never | // ...
ty::Adt(..) | // OutlivesNominalType
- ty::Opaque(..) | // OutlivesNominalType (ish)
ty::Foreign(..) | // OutlivesNominalType
ty::Str | // OutlivesScalar (ish)
ty::Slice(..) | // ...
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index 9922b156e..33543135d 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -87,9 +87,9 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
}
/// Create a new `OutlivesEnvironment` with extra outlives bounds.
- pub fn with_bounds<'a>(
+ pub fn with_bounds(
param_env: ty::ParamEnv<'tcx>,
- infcx: Option<&InferCtxt<'a, 'tcx>>,
+ infcx: Option<&InferCtxt<'tcx>>,
extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
) -> Self {
let mut builder = Self::builder(param_env);
@@ -108,7 +108,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
}
}
-impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> {
+impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
#[inline]
#[instrument(level = "debug")]
fn build(self) -> OutlivesEnvironment<'tcx> {
@@ -125,7 +125,7 @@ impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> {
/// contain inference variables, it must be supplied, in which
/// case we will register "givens" on the inference context. (See
/// `RegionConstraintData`.)
- fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'a, 'tcx>>, outlives_bounds: I)
+ fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'tcx>>, outlives_bounds: I)
where
I: IntoIterator<Item = OutlivesBound<'tcx>>,
{
@@ -142,6 +142,10 @@ impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> {
self.region_bound_pairs
.insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
}
+ OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
+ self.region_bound_pairs
+ .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
+ }
OutlivesBound::RegionSubRegion(r_a, r_b) => {
if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
infcx
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 5bd1774f6..6ca884799 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -68,13 +68,14 @@ use crate::infer::{
};
use crate::traits::{ObligationCause, ObligationCauseCode};
use rustc_data_structures::undo_log::UndoLogs;
+use rustc_hir::def_id::DefId;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable};
use smallvec::smallvec;
-impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Registers that the given region obligation must be resolved
/// from within the scope of `body_id`. These regions are enqueued
/// and later processed by regionck, when full type information is
@@ -182,7 +183,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
outlives_env.param_env,
);
- self.resolve_regions_and_report_errors(generic_param_scope, outlives_env)
+ self.err_ctxt().resolve_regions_and_report_errors(generic_param_scope, outlives_env)
}
}
@@ -283,6 +284,9 @@ where
Component::Param(param_ty) => {
self.param_ty_must_outlive(origin, region, *param_ty);
}
+ Component::Opaque(def_id, substs) => {
+ self.opaque_must_outlive(*def_id, substs, origin, region)
+ }
Component::Projection(projection_ty) => {
self.projection_must_outlive(origin, region, *projection_ty);
}
@@ -314,17 +318,69 @@ where
);
let generic = GenericKind::Param(param_ty);
- let verify_bound = self.verify_bound.generic_bound(generic);
+ let verify_bound = self.verify_bound.param_bound(param_ty);
self.delegate.push_verify(origin, generic, region, verify_bound);
}
#[instrument(level = "debug", skip(self))]
+ fn opaque_must_outlive(
+ &mut self,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ origin: infer::SubregionOrigin<'tcx>,
+ region: ty::Region<'tcx>,
+ ) {
+ self.generic_must_outlive(
+ origin,
+ region,
+ GenericKind::Opaque(def_id, substs),
+ def_id,
+ substs,
+ true,
+ |ty| match *ty.kind() {
+ ty::Opaque(def_id, substs) => (def_id, substs),
+ _ => bug!("expected only projection types from env, not {:?}", ty),
+ },
+ );
+ }
+
+ #[instrument(level = "debug", skip(self))]
fn projection_must_outlive(
&mut self,
origin: infer::SubregionOrigin<'tcx>,
region: ty::Region<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
) {
+ self.generic_must_outlive(
+ origin,
+ region,
+ GenericKind::Projection(projection_ty),
+ projection_ty.item_def_id,
+ projection_ty.substs,
+ false,
+ |ty| match ty.kind() {
+ ty::Projection(projection_ty) => (projection_ty.item_def_id, projection_ty.substs),
+ _ => bug!("expected only projection types from env, not {:?}", ty),
+ },
+ );
+ }
+
+ #[instrument(level = "debug", skip(self, filter))]
+ fn generic_must_outlive(
+ &mut self,
+ origin: infer::SubregionOrigin<'tcx>,
+ region: ty::Region<'tcx>,
+ generic: GenericKind<'tcx>,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ is_opaque: bool,
+ filter: impl Fn(Ty<'tcx>) -> (DefId, SubstsRef<'tcx>),
+ ) {
+ // An optimization for a common case with opaque types.
+ if substs.is_empty() {
+ return;
+ }
+
// This case is thorny for inference. The fundamental problem is
// that there are many cases where we have choice, and inference
// doesn't like choice (the current region inference in
@@ -343,16 +399,15 @@ where
// These are guaranteed to apply, no matter the inference
// results.
let trait_bounds: Vec<_> =
- self.verify_bound.projection_declared_bounds_from_trait(projection_ty).collect();
+ self.verify_bound.declared_region_bounds(def_id, substs).collect();
debug!(?trait_bounds);
// Compute the bounds we can derive from the environment. This
// is an "approximate" match -- in some cases, these bounds
// may not apply.
- let mut approx_env_bounds =
- self.verify_bound.projection_approx_declared_bounds_from_env(projection_ty);
- debug!("projection_must_outlive: approx_env_bounds={:?}", approx_env_bounds);
+ let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(generic);
+ debug!(?approx_env_bounds);
// Remove outlives bounds that we get from the environment but
// which are also deducible from the trait. This arises (cc
@@ -366,14 +421,8 @@ where
// If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait`
// will be invoked with `['b => ^1]` and so we will get `^1` returned.
let bound = bound_outlives.skip_binder();
- match *bound.0.kind() {
- ty::Projection(projection_ty) => self
- .verify_bound
- .projection_declared_bounds_from_trait(projection_ty)
- .all(|r| r != bound.1),
-
- _ => panic!("expected only projection types from env, not {:?}", bound.0),
- }
+ let (def_id, substs) = filter(bound.0);
+ self.verify_bound.declared_region_bounds(def_id, substs).all(|r| r != bound.1)
});
// If declared bounds list is empty, the only applicable rule is
@@ -390,29 +439,11 @@ 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 needs_infer = projection_ty.needs_infer();
- if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer {
- debug!("projection_must_outlive: no declared bounds");
-
- let constraint = origin.to_constraint_category();
- for k in projection_ty.substs {
- match k.unpack() {
- GenericArgKind::Lifetime(lt) => {
- self.delegate.push_sub_region_constraint(
- origin.clone(),
- region,
- lt,
- constraint,
- );
- }
- GenericArgKind::Type(ty) => {
- self.type_must_outlive(origin.clone(), ty, region, constraint);
- }
- GenericArgKind::Const(_) => {
- // Const parameters don't impose constraints.
- }
- }
- }
+ let needs_infer = substs.needs_infer();
+ if approx_env_bounds.is_empty() && trait_bounds.is_empty() && (needs_infer || is_opaque) {
+ debug!("no declared bounds");
+
+ self.substs_must_outlive(substs, origin, region);
return;
}
@@ -442,8 +473,8 @@ where
.all(|b| b == Some(trait_bounds[0]))
{
let unique_bound = trait_bounds[0];
- debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound);
- debug!("projection_must_outlive: unique declared bound appears in trait ref");
+ debug!(?unique_bound);
+ debug!("unique declared bound appears in trait ref");
let category = origin.to_constraint_category();
self.delegate.push_sub_region_constraint(origin, region, unique_bound, category);
return;
@@ -454,14 +485,45 @@ where
// projection outlive; in some cases, this may add insufficient
// edges into the inference graph, leading to inference failures
// even though a satisfactory solution exists.
- let generic = GenericKind::Projection(projection_ty);
- let verify_bound = self.verify_bound.generic_bound(generic);
+ let verify_bound = self.verify_bound.projection_opaque_bounds(
+ generic,
+ def_id,
+ substs,
+ &mut Default::default(),
+ );
debug!("projection_must_outlive: pushing {:?}", verify_bound);
self.delegate.push_verify(origin, generic, region, verify_bound);
}
+
+ fn substs_must_outlive(
+ &mut self,
+ substs: SubstsRef<'tcx>,
+ origin: infer::SubregionOrigin<'tcx>,
+ region: ty::Region<'tcx>,
+ ) {
+ let constraint = origin.to_constraint_category();
+ for k in substs {
+ match k.unpack() {
+ GenericArgKind::Lifetime(lt) => {
+ self.delegate.push_sub_region_constraint(
+ origin.clone(),
+ region,
+ lt,
+ constraint,
+ );
+ }
+ GenericArgKind::Type(ty) => {
+ self.type_must_outlive(origin.clone(), ty, region, constraint);
+ }
+ GenericArgKind::Const(_) => {
+ // Const parameters don't impose constraints.
+ }
+ }
+ }
+ }
}
-impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'tcx> {
+impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'tcx> {
fn push_sub_region_constraint(
&mut self,
origin: SubregionOrigin<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 752334950..f470b2eb8 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -2,11 +2,10 @@ use crate::infer::outlives::components::{compute_components_recursive, Component
use crate::infer::outlives::env::RegionBoundPairs;
use crate::infer::region_constraints::VerifyIfEq;
use crate::infer::{GenericKind, VerifyBound};
-use rustc_data_structures::captures::Captures;
use rustc_data_structures::sso::SsoHashSet;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::{GenericArg, Subst};
-use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, Ty, TyCtxt};
+use rustc_middle::ty::GenericArg;
+use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, SubstsRef, Ty, TyCtxt};
use smallvec::smallvec;
@@ -38,20 +37,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
Self { tcx, region_bound_pairs, implicit_region_bound, param_env }
}
- /// Returns a "verify bound" that encodes what we know about
- /// `generic` and the regions it outlives.
- pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> {
- let mut visited = SsoHashSet::new();
- match generic {
- GenericKind::Param(param_ty) => self.param_bound(param_ty),
- GenericKind::Projection(projection_ty) => {
- self.projection_bound(projection_ty, &mut visited)
- }
- }
- }
-
#[instrument(level = "debug", skip(self))]
- fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
+ pub fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
// Start with anything like `T: 'a` we can scrape from the
// environment. If the environment contains something like
// `for<'a> T: 'a`, then we know that `T` outlives everything.
@@ -105,41 +92,31 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
/// the clause from the environment only applies if `'0 = 'a`,
/// which we don't know yet. But we would still include `'b` in
/// this list.
- pub fn projection_approx_declared_bounds_from_env(
+ pub fn approx_declared_bounds_from_env(
&self,
- projection_ty: ty::ProjectionTy<'tcx>,
+ generic: GenericKind<'tcx>,
) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
- let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx);
+ let projection_ty = generic.to_ty(self.tcx);
let erased_projection_ty = self.tcx.erase_regions(projection_ty);
self.declared_generic_bounds_from_env_for_erased_ty(erased_projection_ty)
}
- /// Searches the where-clauses in scope for regions that
- /// `projection_ty` is known to outlive. Currently requires an
- /// exact match.
- pub fn projection_declared_bounds_from_trait(
+ #[instrument(level = "debug", skip(self, visited))]
+ pub fn projection_opaque_bounds(
&self,
- projection_ty: ty::ProjectionTy<'tcx>,
- ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
- self.declared_projection_bounds_from_trait(projection_ty)
- }
-
- pub fn projection_bound(
- &self,
- projection_ty: ty::ProjectionTy<'tcx>,
+ generic: GenericKind<'tcx>,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
visited: &mut SsoHashSet<GenericArg<'tcx>>,
) -> VerifyBound<'tcx> {
- debug!("projection_bound(projection_ty={:?})", projection_ty);
-
- let projection_ty_as_ty =
- self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
+ let generic_ty = generic.to_ty(self.tcx);
// Search the env for where clauses like `P: 'a`.
- let env_bounds = self
- .projection_approx_declared_bounds_from_env(projection_ty)
+ let projection_opaque_bounds = self
+ .approx_declared_bounds_from_env(generic)
.into_iter()
.map(|binder| {
- if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == projection_ty_as_ty {
+ if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == generic_ty {
// Micro-optimize if this is an exact match (this
// occurs often when there are no region variables
// involved).
@@ -149,21 +126,19 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
VerifyBound::IfEq(verify_if_eq_b)
}
});
-
// Extend with bounds that we can find from the trait.
- let trait_bounds = self
- .projection_declared_bounds_from_trait(projection_ty)
- .map(|r| VerifyBound::OutlivedBy(r));
+ let trait_bounds =
+ self.declared_region_bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r));
// see the extensive comment in projection_must_outlive
let recursive_bound = {
let mut components = smallvec![];
- let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
- compute_components_recursive(self.tcx, ty.into(), &mut components, visited);
+ compute_components_recursive(self.tcx, generic_ty.into(), &mut components, visited);
self.bound_from_components(&components, visited)
};
- VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
+ VerifyBound::AnyBound(projection_opaque_bounds.chain(trait_bounds).collect())
+ .or(recursive_bound)
}
fn bound_from_components(
@@ -195,7 +170,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
match *component {
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
Component::Param(param_ty) => self.param_bound(param_ty),
- Component::Projection(projection_ty) => self.projection_bound(projection_ty, visited),
+ Component::Opaque(did, substs) => self.projection_opaque_bounds(
+ GenericKind::Opaque(did, substs),
+ did,
+ substs,
+ visited,
+ ),
+ Component::Projection(projection_ty) => self.projection_opaque_bounds(
+ GenericKind::Projection(projection_ty),
+ projection_ty.item_def_id,
+ projection_ty.substs,
+ visited,
+ ),
Component::EscapingProjection(ref components) => {
self.bound_from_components(components, visited)
}
@@ -293,30 +279,6 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
/// }
/// ```
///
- /// then this function would return `'x`. This is subject to the
- /// limitations around higher-ranked bounds described in
- /// `region_bounds_declared_on_associated_item`.
- fn declared_projection_bounds_from_trait(
- &self,
- projection_ty: ty::ProjectionTy<'tcx>,
- ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
- debug!("projection_bounds(projection_ty={:?})", projection_ty);
- let tcx = self.tcx;
- self.region_bounds_declared_on_associated_item(projection_ty.item_def_id)
- .map(move |r| EarlyBinder(r).subst(tcx, projection_ty.substs))
- }
-
- /// Given the `DefId` of an associated item, returns any region
- /// bounds attached to that associated item from the trait definition.
- ///
- /// For example:
- ///
- /// ```rust
- /// trait Foo<'a> {
- /// type Bar: 'a;
- /// }
- /// ```
- ///
/// If we were given the `DefId` of `Foo::Bar`, we would return
/// `'a`. You could then apply the substitutions from the
/// projection to convert this into your namespace. This also
@@ -336,17 +298,20 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
///
/// This is for simplicity, and because we are not really smart
/// enough to cope with such bounds anywhere.
- fn region_bounds_declared_on_associated_item(
+ pub fn declared_region_bounds(
&self,
- assoc_item_def_id: DefId,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
) -> impl Iterator<Item = ty::Region<'tcx>> {
let tcx = self.tcx;
- let bounds = tcx.item_bounds(assoc_item_def_id);
+ let bounds = tcx.item_bounds(def_id);
+ trace!("{:#?}", bounds);
bounds
.into_iter()
.filter_map(|p| p.to_opt_type_outlives())
.filter_map(|p| p.no_bound_vars())
.map(|b| b.1)
+ .map(move |r| EarlyBinder(r).subst(tcx, substs))
}
/// Searches through a predicate list for a predicate `T: 'a`.
diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
index b45a6514d..9f12bc972 100644
--- a/compiler/rustc_infer/src/infer/projection.rs
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -6,7 +6,7 @@ use crate::traits::{Obligation, PredicateObligation};
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::InferCtxt;
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Instead of normalizing an associated type projection,
/// this function generates an inference variable and registers
/// an obligation that this inference variable must be the result
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 397efe6ee..90858e307 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
@@ -66,7 +66,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
tcx: TyCtxt<'tcx>,
overly_polymorphic: bool,
max_universe: ty::UniverseIndex,
- snapshot: &CombinedSnapshot<'_, 'tcx>,
+ snapshot: &CombinedSnapshot<'tcx>,
) -> RelateResult<'tcx, ()> {
debug!(
"leak_check(max_universe={:?}, snapshot.universe={:?}, overly_polymorphic={:?})",
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index e43d28ee5..67b3da687 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -12,8 +12,10 @@ 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_hir::def_id::DefId;
use rustc_index::vec::IndexVec;
use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion};
+use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::ReStatic;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{ReLateBound, ReVar};
@@ -168,6 +170,7 @@ pub struct Verify<'tcx> {
pub enum GenericKind<'tcx> {
Param(ty::ParamTy),
Projection(ty::ProjectionTy<'tcx>),
+ Opaque(DefId, SubstsRef<'tcx>),
}
/// Describes the things that some `GenericKind` value `G` is known to
@@ -747,6 +750,9 @@ impl<'tcx> fmt::Debug for GenericKind<'tcx> {
match *self {
GenericKind::Param(ref p) => write!(f, "{:?}", p),
GenericKind::Projection(ref p) => write!(f, "{:?}", p),
+ GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
+ write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
+ }),
}
}
}
@@ -756,6 +762,9 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> {
match *self {
GenericKind::Param(ref p) => write!(f, "{}", p),
GenericKind::Projection(ref p) => write!(f, "{}", p),
+ GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
+ write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
+ }),
}
}
}
@@ -765,6 +774,7 @@ impl<'tcx> GenericKind<'tcx> {
match *self {
GenericKind::Param(ref p) => p.to_ty(tcx),
GenericKind::Projection(ref p) => tcx.mk_projection(p.item_def_id, p.substs),
+ GenericKind::Opaque(def_id, substs) => tcx.mk_opaque(def_id, substs),
}
}
}
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 3d99f0958..4db4ff238 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -1,6 +1,5 @@
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::{FixupError, FixupResult, InferCtxt, Span};
-use rustc_middle::mir;
use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor};
use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable};
@@ -16,12 +15,12 @@ use std::ops::ControlFlow;
/// useful for printing messages etc but also required at various
/// points for correctness.
pub struct OpportunisticVarResolver<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> {
#[inline]
- pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
+ pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
OpportunisticVarResolver { infcx }
}
}
@@ -32,7 +31,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- if !t.has_infer_types_or_consts() {
+ if !t.has_non_region_infer() {
t // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
let t = self.infcx.shallow_resolve(t);
@@ -41,17 +40,13 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
}
fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> {
- if !ct.has_infer_types_or_consts() {
+ if !ct.has_non_region_infer() {
ct // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
let ct = self.infcx.shallow_resolve(ct);
ct.super_fold_with(self)
}
}
-
- fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
- constant.super_fold_with(self)
- }
}
/// The opportunistic region resolver opportunistically resolves regions
@@ -62,11 +57,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
/// If you want to resolve type and const variables as well, call
/// [InferCtxt::resolve_vars_if_possible] first.
pub struct OpportunisticRegionResolver<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> OpportunisticRegionResolver<'a, 'tcx> {
- pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
+ pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
OpportunisticRegionResolver { infcx }
}
}
@@ -116,11 +111,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
/// It does not construct the fully resolved type (which might
/// involve some hashing and so forth).
pub struct UnresolvedTypeFinder<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> {
- pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
+ pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
UnresolvedTypeFinder { infcx }
}
}
@@ -167,7 +162,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
/// Full type resolution replaces all type and region variables with
/// their concrete results. If any variable cannot be replaced (never unified, etc)
/// then an `Err` result is returned.
-pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: T) -> FixupResult<'tcx, T>
+pub fn fully_resolve<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult<'tcx, T>
where
T: TypeFoldable<'tcx>,
{
@@ -177,7 +172,7 @@ where
// N.B. This type is not public because the protocol around checking the
// `err` field is not enforceable otherwise.
struct FullTypeResolver<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index b7eab5d43..97354ba5d 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -2,9 +2,7 @@ use super::combine::{CombineFields, RelationDir};
use super::SubregionOrigin;
use crate::infer::combine::ConstEquateRelation;
-use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::traits::Obligation;
-use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::TyVar;
@@ -12,8 +10,8 @@ use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
use std::mem;
/// Ensures `a` is made a subtype of `b`. Returns `a` on success.
-pub struct Sub<'combine, 'infcx, 'tcx> {
- fields: &'combine mut CombineFields<'infcx, 'tcx>,
+pub struct Sub<'combine, 'a, 'tcx> {
+ fields: &'combine mut CombineFields<'a, 'tcx>,
a_is_expected: bool,
}
@@ -130,39 +128,36 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
(&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
if self.fields.define_opaque_types && did.is_local() =>
{
- let mut generalize = |ty, ty_is_expected| {
- let var = infcx.next_ty_var_id_in_universe(
- TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
- span: self.fields.trace.cause.span,
- },
- ty::UniverseIndex::ROOT,
- );
- self.fields.instantiate(ty, RelationDir::SubtypeOf, var, ty_is_expected)?;
- Ok(infcx.tcx.mk_ty_var(var))
- };
- let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) };
- let (ga, gb) = match (a.kind(), b.kind()) {
- (&ty::Opaque(..), _) => (a, generalize(b, true)?),
- (_, &ty::Opaque(..)) => (generalize(a, false)?, b),
- _ => unreachable!(),
- };
self.fields.obligations.extend(
infcx
- .handle_opaque_type(ga, gb, true, &self.fields.trace.cause, self.param_env())
- // Don't leak any generalized type variables out of this
- // subtyping relation in the case of a type error.
- .map_err(|err| {
- let (ga, gb) = self.fields.infcx.resolve_vars_if_possible((ga, gb));
- if let TypeError::Sorts(sorts) = err && sorts.expected == ga && sorts.found == gb {
- TypeError::Sorts(ExpectedFound { expected: a, found: b })
- } else {
- err
- }
- })?
+ .handle_opaque_type(
+ a,
+ b,
+ self.a_is_expected,
+ &self.fields.trace.cause,
+ self.param_env(),
+ )?
.obligations,
);
- Ok(ga)
+ Ok(a)
+ }
+ // Optimization of GeneratorWitness relation since we know that all
+ // free regions are replaced with bound regions during construction.
+ // This greatly speeds up subtyping of GeneratorWitness.
+ (&ty::GeneratorWitness(a_types), &ty::GeneratorWitness(b_types)) => {
+ let a_types = infcx.tcx.anonymize_bound_vars(a_types);
+ let b_types = infcx.tcx.anonymize_bound_vars(b_types);
+ if a_types.bound_vars() == b_types.bound_vars() {
+ let (a_types, b_types) = infcx.replace_bound_vars_with_placeholders(
+ a_types.map_bound(|a_types| (a_types, b_types.skip_binder())),
+ );
+ for (a, b) in std::iter::zip(a_types, b_types) {
+ self.relate(a, b)?;
+ }
+ Ok(a)
+ } else {
+ Err(ty::error::TypeError::Sorts(ty::relate::expected_found(self, a, b)))
+ }
}
_ => {
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index ef60d2c91..e040634ed 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -2,7 +2,7 @@
//!
//! - **Type inference.** The type inference code can be found in the `infer` module;
//! this code handles low-level equality and subtyping operations. The
-//! type check pass in the compiler is found in the `rustc_typeck` crate.
+//! type check pass in the compiler is found in the `rustc_hir_analysis` crate.
//!
//! For more information about how rustc works, see the [rustc dev guide].
//!
@@ -17,9 +17,8 @@
#![feature(box_patterns)]
#![feature(control_flow_enum)]
#![feature(extend_one)]
-#![cfg_attr(bootstrap, feature(label_break_value))]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
+#![feature(if_let_guard)]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(try_blocks)]
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index 736278ba0..b2b985a22 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -10,7 +10,7 @@ use super::{ObligationCause, PredicateObligation};
pub trait TraitEngine<'tcx>: 'tcx {
fn normalize_projection_type(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
cause: ObligationCause<'tcx>,
@@ -21,7 +21,7 @@ pub trait TraitEngine<'tcx>: 'tcx {
/// parameters (except for `Self`).
fn register_bound(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
def_id: DefId,
@@ -41,14 +41,13 @@ pub trait TraitEngine<'tcx>: 'tcx {
fn register_predicate_obligation(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
obligation: PredicateObligation<'tcx>,
);
- fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>>;
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
- fn select_where_possible(&mut self, infcx: &InferCtxt<'_, 'tcx>)
- -> Vec<FulfillmentError<'tcx>>;
+ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
@@ -58,7 +57,7 @@ pub trait TraitEngine<'tcx>: 'tcx {
pub trait TraitEngineExt<'tcx> {
fn register_predicate_obligations(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
);
}
@@ -66,7 +65,7 @@ pub trait TraitEngineExt<'tcx> {
impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
fn register_predicate_obligations(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
) {
for obligation in obligations {
diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
index 95b6c4ce1..f8b5009a5 100644
--- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
@@ -10,7 +10,7 @@ use rustc_span::Span;
use std::fmt;
use std::iter;
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
pub fn report_extra_impl_obligation(
&self,
error_span: Span,
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 4df4de21a..c8600ded9 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -67,6 +67,14 @@ impl<'tcx> PredicateObligation<'tcx> {
recursion_depth: self.recursion_depth,
})
}
+
+ pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> PredicateObligation<'tcx> {
+ self.param_env = self.param_env.without_const();
+ if let ty::PredicateKind::Trait(trait_pred) = self.predicate.kind().skip_binder() && trait_pred.is_const_if_const() {
+ self.predicate = tcx.mk_predicate(self.predicate.kind().map_bound(|_| ty::PredicateKind::Trait(trait_pred.without_const())));
+ }
+ self
+ }
}
impl<'tcx> TraitObligation<'tcx> {
@@ -105,6 +113,8 @@ 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>>>),
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/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index 573d2d1e3..1c6ab6a08 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -47,6 +47,7 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
write!(f, "CodeConstEquateError({:?}, {:?})", a, b)
}
super::CodeAmbiguity => write!(f, "Ambiguity"),
+ super::CodeCycle(ref cycle) => write!(f, "Cycle({:?})", cycle),
}
}
}
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index f5a1edf6d..e12c069dc 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -246,6 +246,13 @@ impl<'tcx> Elaborator<'tcx> {
Component::UnresolvedInferenceVariable(_) => None,
+ Component::Opaque(def_id, substs) => {
+ let ty = tcx.mk_opaque(def_id, substs);
+ Some(ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
+ ty, r_min,
+ )))
+ }
+
Component::Projection(projection) => {
// We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
// With this, we can deduce that `<Bar as Baz>::Assoc: 'a`.
@@ -262,8 +269,9 @@ impl<'tcx> Elaborator<'tcx> {
None
}
})
- .map(ty::Binder::dummy)
- .map(|predicate_kind| predicate_kind.to_predicate(tcx))
+ .map(|predicate_kind| {
+ bound_predicate.rebind(predicate_kind).to_predicate(tcx)
+ })
.filter(|&predicate| visited.insert(predicate))
.map(|predicate| {
predicate_obligation(
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index da4002d09..6a4c5b4d3 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
libloading = "0.7.1"
@@ -38,7 +37,8 @@ rustc_mir_build = { path = "../rustc_mir_build" }
rustc_mir_transform = { path = "../rustc_mir_transform" }
rustc_monomorphize = { path = "../rustc_monomorphize" }
rustc_passes = { path = "../rustc_passes" }
-rustc_typeck = { path = "../rustc_typeck" }
+rustc_hir_analysis = { path = "../rustc_hir_analysis" }
+rustc_hir_typeck = { path = "../rustc_hir_typeck" }
rustc_lint = { path = "../rustc_lint" }
rustc_errors = { path = "../rustc_errors" }
rustc_plugin_impl = { path = "../rustc_plugin_impl" }
diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs
index 6a497aed4..f5135c78d 100644
--- a/compiler/rustc_interface/src/errors.rs
+++ b/compiler/rustc_interface/src/errors.rs
@@ -1,11 +1,11 @@
-use rustc_macros::SessionDiagnostic;
+use rustc_macros::Diagnostic;
use rustc_span::{Span, Symbol};
use std::io;
use std::path::Path;
-#[derive(SessionDiagnostic)]
-#[diag(interface::ferris_identifier)]
+#[derive(Diagnostic)]
+#[diag(interface_ferris_identifier)]
pub struct FerrisIdentifier {
#[primary_span]
pub spans: Vec<Span>,
@@ -13,76 +13,76 @@ pub struct FerrisIdentifier {
pub first_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(interface::emoji_identifier)]
+#[derive(Diagnostic)]
+#[diag(interface_emoji_identifier)]
pub struct EmojiIdentifier {
#[primary_span]
pub spans: Vec<Span>,
pub ident: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(interface::mixed_bin_crate)]
+#[derive(Diagnostic)]
+#[diag(interface_mixed_bin_crate)]
pub struct MixedBinCrate;
-#[derive(SessionDiagnostic)]
-#[diag(interface::mixed_proc_macro_crate)]
+#[derive(Diagnostic)]
+#[diag(interface_mixed_proc_macro_crate)]
pub struct MixedProcMacroCrate;
-#[derive(SessionDiagnostic)]
-#[diag(interface::proc_macro_doc_without_arg)]
+#[derive(Diagnostic)]
+#[diag(interface_proc_macro_doc_without_arg)]
pub struct ProcMacroDocWithoutArg;
-#[derive(SessionDiagnostic)]
-#[diag(interface::error_writing_dependencies)]
+#[derive(Diagnostic)]
+#[diag(interface_error_writing_dependencies)]
pub struct ErrorWritingDependencies<'a> {
pub path: &'a Path,
pub error: io::Error,
}
-#[derive(SessionDiagnostic)]
-#[diag(interface::input_file_would_be_overwritten)]
+#[derive(Diagnostic)]
+#[diag(interface_input_file_would_be_overwritten)]
pub struct InputFileWouldBeOverWritten<'a> {
pub path: &'a Path,
}
-#[derive(SessionDiagnostic)]
-#[diag(interface::generated_file_conflicts_with_directory)]
+#[derive(Diagnostic)]
+#[diag(interface_generated_file_conflicts_with_directory)]
pub struct GeneratedFileConflictsWithDirectory<'a> {
pub input_path: &'a Path,
pub dir_path: &'a Path,
}
-#[derive(SessionDiagnostic)]
-#[diag(interface::temps_dir_error)]
+#[derive(Diagnostic)]
+#[diag(interface_temps_dir_error)]
pub struct TempsDirError;
-#[derive(SessionDiagnostic)]
-#[diag(interface::out_dir_error)]
+#[derive(Diagnostic)]
+#[diag(interface_out_dir_error)]
pub struct OutDirError;
-#[derive(SessionDiagnostic)]
-#[diag(interface::cant_emit_mir)]
+#[derive(Diagnostic)]
+#[diag(interface_cant_emit_mir)]
pub struct CantEmitMIR {
pub error: io::Error,
}
-#[derive(SessionDiagnostic)]
-#[diag(interface::rustc_error_fatal)]
+#[derive(Diagnostic)]
+#[diag(interface_rustc_error_fatal)]
pub struct RustcErrorFatal {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(interface::rustc_error_unexpected_annotation)]
+#[derive(Diagnostic)]
+#[diag(interface_rustc_error_unexpected_annotation)]
pub struct RustcErrorUnexpectedAnnotation {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(interface::failed_writing_file)]
+#[derive(Diagnostic)]
+#[diag(interface_failed_writing_file)]
pub struct FailedWritingFile<'a> {
pub path: &'a Path,
pub error: io::Error,
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 949bd02ad..89aaa0b95 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -17,7 +17,7 @@ use rustc_session::config::{self, CheckCfg, ErrorOutputType, Input, OutputFilena
use rustc_session::early_error;
use rustc_session::lint;
use rustc_session::parse::{CrateConfig, ParseSess};
-use rustc_session::{DiagnosticOutput, Session};
+use rustc_session::Session;
use rustc_span::source_map::{FileLoader, FileName};
use rustc_span::symbol::sym;
use std::path::PathBuf;
@@ -25,7 +25,10 @@ use std::result;
pub type Result<T> = result::Result<T, ErrorGuaranteed>;
-/// Represents a compiler session.
+/// Represents a compiler session. Note that every `Compiler` contains a
+/// `Session`, but `Compiler` also contains some things that cannot be in
+/// `Session`, due to `Session` being in a crate that has many fewer
+/// dependencies than this crate.
///
/// Can be used to run `rustc_interface` queries.
/// Created by passing [`Config`] to [`run_compiler`].
@@ -247,7 +250,6 @@ pub struct Config {
pub output_dir: Option<PathBuf>,
pub output_file: Option<PathBuf>,
pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
- pub diagnostic_output: DiagnosticOutput,
pub lint_caps: FxHashMap<lint::LintId, lint::Level>,
@@ -276,59 +278,6 @@ pub struct Config {
pub registry: Registry,
}
-pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R) -> R {
- crate::callbacks::setup_callbacks();
-
- let registry = &config.registry;
- let (mut sess, codegen_backend) = util::create_session(
- config.opts,
- config.crate_cfg,
- config.crate_check_cfg,
- config.diagnostic_output,
- config.file_loader,
- config.input_path.clone(),
- config.lint_caps,
- config.make_codegen_backend,
- registry.clone(),
- );
-
- if let Some(parse_sess_created) = config.parse_sess_created {
- parse_sess_created(
- &mut Lrc::get_mut(&mut sess)
- .expect("create_session() should never share the returned session")
- .parse_sess,
- );
- }
-
- let temps_dir = sess.opts.unstable_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o));
-
- let compiler = Compiler {
- sess,
- codegen_backend,
- input: config.input,
- input_path: config.input_path,
- output_dir: config.output_dir,
- output_file: config.output_file,
- temps_dir,
- register_lints: config.register_lints,
- override_queries: config.override_queries,
- };
-
- rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
- let r = {
- let _sess_abort_error = OnDrop(|| {
- compiler.sess.finish_diagnostics(registry);
- });
-
- f(&compiler)
- };
-
- let prof = compiler.sess.prof.clone();
- prof.generic_activity("drop_compiler").run(move || drop(compiler));
- r
- })
-}
-
// JUSTIFICATION: before session exists, only config
#[allow(rustc::bad_opt_access)]
pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
@@ -336,7 +285,53 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
util::run_in_thread_pool_with_globals(
config.opts.edition,
config.opts.unstable_opts.threads,
- || create_compiler_and_run(config, f),
+ || {
+ crate::callbacks::setup_callbacks();
+
+ let registry = &config.registry;
+ let (mut sess, codegen_backend) = util::create_session(
+ config.opts,
+ config.crate_cfg,
+ config.crate_check_cfg,
+ config.file_loader,
+ config.input_path.clone(),
+ config.lint_caps,
+ config.make_codegen_backend,
+ registry.clone(),
+ );
+
+ if let Some(parse_sess_created) = config.parse_sess_created {
+ parse_sess_created(&mut sess.parse_sess);
+ }
+
+ let temps_dir = sess.opts.unstable_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o));
+
+ let compiler = Compiler {
+ sess: Lrc::new(sess),
+ codegen_backend: Lrc::new(codegen_backend),
+ input: config.input,
+ input_path: config.input_path,
+ output_dir: config.output_dir,
+ output_file: config.output_file,
+ temps_dir,
+ register_lints: config.register_lints,
+ override_queries: config.override_queries,
+ };
+
+ rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
+ let r = {
+ let _sess_abort_error = OnDrop(|| {
+ compiler.sess.finish_diagnostics(registry);
+ });
+
+ f(&compiler)
+ };
+
+ let prof = compiler.sess.prof.clone();
+ prof.generic_activity("drop_compiler").run(move || drop(compiler));
+ r
+ })
+ },
)
}
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 41cd7b0e9..a41a749ee 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -1,5 +1,4 @@
#![feature(box_patterns)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(internal_output_capture)]
#![feature(thread_spawn_unchecked)]
#![feature(once_cell)]
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index c41b154c3..7f1d21bf1 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -16,7 +16,6 @@ use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
use rustc_errors::{ErrorGuaranteed, PResult};
use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
use rustc_hir::def_id::StableCrateId;
-use rustc_hir::definitions::Definitions;
use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore};
use rustc_metadata::creader::CStore;
use rustc_middle::arena::Arena;
@@ -30,14 +29,13 @@ use rustc_plugin_impl as plugin;
use rustc_query_impl::{OnDiskCache, Queries as TcxQueries};
use rustc_resolve::{Resolver, ResolverArenas};
use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
-use rustc_session::cstore::{CrateStoreDyn, MetadataLoader, MetadataLoaderDyn};
+use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn};
use rustc_session::output::filename_for_input;
use rustc_session::search_paths::PathKind;
use rustc_session::{Limit, Session};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::FileName;
use rustc_trait_selection::traits;
-use rustc_typeck as typeck;
use std::any::Any;
use std::cell::RefCell;
@@ -136,10 +134,7 @@ mod boxed_resolver {
f((&mut *resolver).as_mut().unwrap())
}
- pub fn to_resolver_outputs(
- resolver: Rc<RefCell<BoxedResolver>>,
- ) -> (Definitions, Box<CrateStoreDyn>, ty::ResolverOutputs, ty::ResolverAstLowering)
- {
+ pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ty::ResolverOutputs {
match Rc::try_unwrap(resolver) {
Ok(resolver) => {
let mut resolver = resolver.into_inner();
@@ -736,11 +731,11 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
rustc_mir_transform::provide(providers);
rustc_monomorphize::provide(providers);
rustc_privacy::provide(providers);
- typeck::provide(providers);
+ rustc_hir_analysis::provide(providers);
+ rustc_hir_typeck::provide(providers);
ty::provide(providers);
traits::provide(providers);
rustc_passes::provide(providers);
- rustc_resolve::provide(providers);
rustc_traits::provide(providers);
rustc_ty_utils::provide(providers);
rustc_metadata::provide(providers);
@@ -789,8 +784,7 @@ pub fn create_global_ctxt<'tcx>(
// incr. comp. yet.
dep_graph.assert_ignored();
- let (definitions, cstore, resolver_outputs, resolver_for_lowering) =
- BoxedResolver::to_resolver_outputs(resolver);
+ let resolver_outputs = BoxedResolver::to_resolver_outputs(resolver);
let sess = &compiler.session();
let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
@@ -817,10 +811,7 @@ pub fn create_global_ctxt<'tcx>(
lint_store,
arena,
hir_arena,
- definitions,
- cstore,
resolver_outputs,
- resolver_for_lowering,
krate,
dep_graph,
queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn),
@@ -880,7 +871,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
});
// passes are timed inside typeck
- typeck::check_crate(tcx)?;
+ rustc_hir_analysis::check_crate(tcx)?;
sess.time("misc_checking_2", || {
parallel!(
@@ -936,7 +927,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
sess.time("misc_checking_3", || {
parallel!(
{
- tcx.ensure().privacy_access_levels(());
+ tcx.ensure().effective_visibilities(());
parallel!(
{
diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs
index 5371c513d..4c236c693 100644
--- a/compiler/rustc_interface/src/proc_macro_decls.rs
+++ b/compiler/rustc_interface/src/proc_macro_decls.rs
@@ -1,4 +1,3 @@
-use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
@@ -10,7 +9,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> {
for id in tcx.hir().items() {
let attrs = finder.tcx.hir().attrs(id.hir_id());
if finder.tcx.sess.contains_name(attrs, sym::rustc_proc_macro_decls) {
- finder.decls = Some(id.def_id);
+ finder.decls = Some(id.owner_id.def_id);
}
}
@@ -19,7 +18,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> {
struct Finder<'tcx> {
tcx: TyCtxt<'tcx>,
- decls: Option<hir::def_id::LocalDefId>,
+ decls: Option<LocalDefId>,
}
pub(crate) fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 6c725a01b..91d180e1e 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -246,6 +246,10 @@ impl<'tcx> Queries<'tcx> {
// Don't do code generation if there were any errors
self.session().compile_status()?;
+ // If we have any delayed bugs, for example because we created TyKind::Error earlier,
+ // it's likely that codegen will only cause more ICEs, obscuring the original problem
+ self.session().diagnostic().flush_delayed();
+
// Hook for UI tests.
Self::check_for_rustc_errors_attr(tcx);
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index c7615a577..eb8e65a6d 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -17,7 +17,7 @@ use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, Switc
use rustc_session::lint::Level;
use rustc_session::search_paths::SearchPath;
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
-use rustc_session::{build_session, getopts, DiagnosticOutput, Session};
+use rustc_session::{build_session, getopts, Session};
use rustc_span::edition::{Edition, DEFAULT_EDITION};
use rustc_span::symbol::sym;
use rustc_span::SourceFileHashAlgorithm;
@@ -40,16 +40,7 @@ fn build_session_options_and_crate_config(matches: getopts::Matches) -> (Options
fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
let registry = registry::Registry::new(&[]);
let (sessopts, cfg) = build_session_options_and_crate_config(matches);
- let sess = build_session(
- sessopts,
- None,
- None,
- registry,
- DiagnosticOutput::Default,
- Default::default(),
- None,
- None,
- );
+ let sess = build_session(sessopts, None, None, registry, Default::default(), None, None);
(sess, cfg)
}
@@ -540,7 +531,7 @@ fn test_codegen_options_tracking_hash() {
}
// Make sure that changing an [UNTRACKED] option leaves the hash unchanged.
- // This list is in alphabetical order.
+ // tidy-alphabetical-start
untracked!(ar, String::from("abc"));
untracked!(codegen_units, Some(42));
untracked!(default_linker_libraries, true);
@@ -556,6 +547,7 @@ fn test_codegen_options_tracking_hash() {
untracked!(rpath, true);
untracked!(save_temps, true);
untracked!(strip, Strip::Debuginfo);
+ // tidy-alphabetical-end
macro_rules! tracked {
($name: ident, $non_default_value: expr) => {
@@ -567,7 +559,7 @@ fn test_codegen_options_tracking_hash() {
}
// Make sure that changing a [TRACKED] option changes the hash.
- // This list is in alphabetical order.
+ // tidy-alphabetical-start
tracked!(code_model, Some(CodeModel::Large));
tracked!(control_flow_guard, CFGuard::Checks);
tracked!(debug_assertions, Some(true));
@@ -577,8 +569,8 @@ fn test_codegen_options_tracking_hash() {
tracked!(force_unwind_tables, Some(true));
tracked!(inline_threshold, Some(0xf007ba11));
tracked!(instrument_coverage, Some(InstrumentCoverage::All));
- tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
tracked!(link_dead_code, Some(true));
+ tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
tracked!(llvm_args, vec![String::from("1"), String::from("2")]);
tracked!(lto, LtoCli::Fat);
tracked!(metadata, vec![String::from("A"), String::from("B")]);
@@ -599,6 +591,7 @@ fn test_codegen_options_tracking_hash() {
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
tracked!(target_cpu, Some(String::from("abc")));
tracked!(target_feature, String::from("all the features, all of them"));
+ // tidy-alphabetical-end
}
#[test]
@@ -619,12 +612,13 @@ fn test_top_level_options_tracked_no_crate() {
}
// Make sure that changing a [TRACKED_NO_CRATE_HASH] option leaves the crate hash unchanged but changes the incremental hash.
- // This list is in alphabetical order.
- tracked!(remap_path_prefix, vec![("/home/bors/rust".into(), "src".into())]);
+ // tidy-alphabetical-start
tracked!(
real_rust_source_base_dir,
Some("/home/bors/rust/.rustup/toolchains/nightly/lib/rustlib/src/rust".into())
);
+ tracked!(remap_path_prefix, vec![("/home/bors/rust".into(), "src".into())]);
+ // tidy-alphabetical-end
}
#[test]
@@ -641,7 +635,7 @@ fn test_unstable_options_tracking_hash() {
}
// Make sure that changing an [UNTRACKED] option leaves the hash unchanged.
- // This list is in alphabetical order.
+ // tidy-alphabetical-start
untracked!(assert_incr_state, Some(String::from("loaded")));
untracked!(deduplicate_diagnostics, false);
untracked!(dep_tasks, true);
@@ -654,6 +648,7 @@ fn test_unstable_options_tracking_hash() {
untracked!(dump_mir_dir, String::from("abc"));
untracked!(dump_mir_exclude_pass_number, true);
untracked!(dump_mir_graphviz, true);
+ untracked!(dylib_lto, true);
untracked!(emit_stack_sizes, true);
untracked!(future_incompat_test, true);
untracked!(hir_stats, true);
@@ -678,12 +673,12 @@ fn test_unstable_options_tracking_hash() {
untracked!(perf_stats, true);
// `pre_link_arg` is omitted because it just forwards to `pre_link_args`.
untracked!(pre_link_args, vec![String::from("abc"), String::from("def")]);
- untracked!(profile_closures, true);
untracked!(print_llvm_passes, true);
untracked!(print_mono_items, Some(String::from("abc")));
untracked!(print_type_sizes, true);
untracked!(proc_macro_backtrace, true);
untracked!(proc_macro_execution_strategy, ProcMacroExecutionStrategy::CrossThread);
+ untracked!(profile_closures, true);
untracked!(query_dep_graph, true);
untracked!(save_analysis, true);
untracked!(self_profile, SwitchWithOptPath::Enabled(None));
@@ -692,7 +687,6 @@ fn test_unstable_options_tracking_hash() {
untracked!(span_free_formats, true);
untracked!(temps_dir, Some(String::from("abc")));
untracked!(threads, 99);
- untracked!(time, true);
untracked!(time_llvm_passes, true);
untracked!(time_passes, true);
untracked!(trace_macros, true);
@@ -702,6 +696,7 @@ fn test_unstable_options_tracking_hash() {
untracked!(unstable_options, true);
untracked!(validate_mir, true);
untracked!(verbose, true);
+ // tidy-alphabetical-end
macro_rules! tracked {
($name: ident, $non_default_value: expr) => {
@@ -713,7 +708,7 @@ fn test_unstable_options_tracking_hash() {
}
// Make sure that changing a [TRACKED] option changes the hash.
- // This list is in alphabetical order.
+ // tidy-alphabetical-start
tracked!(allow_features, Some(vec![String::from("lang_items")]));
tracked!(always_encode_mir, true);
tracked!(asm_comments, true);
@@ -734,10 +729,10 @@ fn test_unstable_options_tracking_hash() {
tracked!(debug_macros, true);
tracked!(dep_info_omit_d_target, true);
tracked!(drop_tracking, true);
- tracked!(export_executable_symbols, true);
tracked!(dual_proc_macros, true);
tracked!(dwarf_version, Some(5));
tracked!(emit_thin_lto, false);
+ tracked!(export_executable_symbols, true);
tracked!(fewer_names, Some(true));
tracked!(force_unstable_if_unmarked, true);
tracked!(fuel, Some(("abc".to_string(), 99)));
@@ -758,11 +753,10 @@ fn test_unstable_options_tracking_hash() {
tracked!(mir_opt_level, Some(4));
tracked!(move_size_limit, Some(4096));
tracked!(mutable_noalias, Some(true));
- tracked!(new_llvm_pass_manager, Some(true));
tracked!(no_generate_arange_section, true);
tracked!(no_link, true);
- tracked!(no_unique_section_names, true);
tracked!(no_profiler_runtime, true);
+ tracked!(no_unique_section_names, true);
tracked!(oom, OomStrategy::Panic);
tracked!(osx_rpath_install_name, true);
tracked!(packed_bundled_libs, true);
@@ -775,8 +769,8 @@ fn test_unstable_options_tracking_hash() {
tracked!(print_fuel, Some("abc".to_string()));
tracked!(profile, true);
tracked!(profile_emit, Some(PathBuf::from("abc")));
- tracked!(profiler_runtime, "abc".to_string());
tracked!(profile_sample_use, Some(PathBuf::from("abc")));
+ tracked!(profiler_runtime, "abc".to_string());
tracked!(relax_elf_relocations, Some(true));
tracked!(relro_level, Some(RelroLevel::Full));
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
@@ -805,6 +799,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(verify_llvm_ir, true);
tracked!(virtual_function_elimination, true);
tracked!(wasi_exec_model, Some(WasiExecModel::Reactor));
+ // tidy-alphabetical-end
macro_rules! tracked_no_crate_hash {
($name: ident, $non_default_value: expr) => {
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index f7e70d355..519b8a7fc 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -3,22 +3,15 @@ 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::jobserver;
-use rustc_data_structures::sync::Lrc;
use rustc_errors::registry::Registry;
-#[cfg(parallel_compiler)]
-use rustc_middle::ty::tls;
use rustc_parse::validate_attr;
-#[cfg(parallel_compiler)]
-use rustc_query_impl::{QueryContext, QueryCtxt};
use rustc_session as session;
use rustc_session::config::CheckCfg;
use rustc_session::config::{self, CrateType};
use rustc_session::config::{ErrorOutputType, Input, OutputFilenames};
use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
use rustc_session::parse::CrateConfig;
-use rustc_session::{early_error, filesearch, output, DiagnosticOutput, Session};
+use rustc_session::{early_error, filesearch, output, Session};
use rustc_span::edition::Edition;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::FileLoader;
@@ -26,8 +19,6 @@ use rustc_span::symbol::{sym, Symbol};
use std::env;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::mem;
-#[cfg(not(parallel_compiler))]
-use std::panic;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::OnceLock;
@@ -65,7 +56,6 @@ pub fn create_session(
sopts: config::Options,
cfg: FxHashSet<(String, Option<String>)>,
check_cfg: CheckCfg,
- diagnostic_output: DiagnosticOutput,
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
input_path: Option<PathBuf>,
lint_caps: FxHashMap<lint::LintId, lint::Level>,
@@ -73,7 +63,7 @@ pub fn create_session(
Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
>,
descriptions: Registry,
-) -> (Lrc<Session>, Lrc<Box<dyn CodegenBackend>>) {
+) -> (Session, Box<dyn CodegenBackend>) {
let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
make_codegen_backend(&sopts)
} else {
@@ -104,7 +94,6 @@ pub fn create_session(
input_path,
bundle,
descriptions,
- diagnostic_output,
lint_caps,
file_loader,
target_override,
@@ -121,7 +110,7 @@ pub fn create_session(
sess.parse_sess.config = cfg;
sess.parse_sess.check_config = check_cfg;
- (Lrc::new(sess), Lrc::new(codegen_backend))
+ (sess, codegen_backend)
}
const STACK_SIZE: usize = 8 * 1024 * 1024;
@@ -132,79 +121,86 @@ fn get_stack_size() -> Option<usize> {
env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE)
}
-/// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need
-/// for `'static` bounds.
-#[cfg(not(parallel_compiler))]
-fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) -> R {
- // SAFETY: join() is called immediately, so any closure captures are still
- // alive.
- match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() {
- Ok(v) => v,
- Err(e) => panic::resume_unwind(e),
- }
-}
-
#[cfg(not(parallel_compiler))]
-pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
+pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
edition: Edition,
_threads: usize,
f: F,
) -> R {
- let mut cfg = thread::Builder::new().name("rustc".to_string());
-
+ // The "thread pool" is a single spawned thread in the non-parallel
+ // compiler. We run on a spawned thread instead of the main thread (a) to
+ // provide control over the stack size, and (b) to increase similarity with
+ // the parallel compiler, in particular to ensure there is no accidental
+ // sharing of data between the main thread and the compilation thread
+ // (which might cause problems for the parallel compiler).
+ let mut builder = thread::Builder::new().name("rustc".to_string());
if let Some(size) = get_stack_size() {
- cfg = cfg.stack_size(size);
+ builder = builder.stack_size(size);
}
- let main_handler = move || rustc_span::create_session_globals_then(edition, f);
-
- scoped_thread(cfg, main_handler)
-}
-
-/// Creates a new thread and forwards information in thread locals to it.
-/// The new thread runs the deadlock handler.
-/// Must only be called when a deadlock is about to happen.
-#[cfg(parallel_compiler)]
-unsafe fn handle_deadlock() {
- let registry = rustc_rayon_core::Registry::current();
-
- let query_map = tls::with(|tcx| {
- QueryCtxt::from_tcx(tcx)
- .try_collect_active_jobs()
- .expect("active jobs shouldn't be locked in deadlock handler")
- });
- thread::spawn(move || rustc_query_impl::deadlock(query_map, &registry));
+ // We build the session globals and run `f` on the spawned thread, because
+ // `SessionGlobals` does not impl `Send` in the non-parallel compiler.
+ thread::scope(|s| {
+ // `unwrap` is ok here because `spawn_scoped` only panics if the thread
+ // name contains null bytes.
+ let r = builder
+ .spawn_scoped(s, move || rustc_span::create_session_globals_then(edition, f))
+ .unwrap()
+ .join();
+
+ match r {
+ Ok(v) => v,
+ Err(e) => std::panic::resume_unwind(e),
+ }
+ })
}
#[cfg(parallel_compiler)]
-pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
+pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
edition: Edition,
threads: usize,
f: F,
) -> R {
- let mut config = rayon::ThreadPoolBuilder::new()
+ use rustc_data_structures::jobserver;
+ use rustc_middle::ty::tls;
+ use rustc_query_impl::{deadlock, QueryContext, QueryCtxt};
+
+ let mut builder = rayon::ThreadPoolBuilder::new()
.thread_name(|_| "rustc".to_string())
.acquire_thread_handler(jobserver::acquire_thread)
.release_thread_handler(jobserver::release_thread)
.num_threads(threads)
- .deadlock_handler(|| unsafe { handle_deadlock() });
-
+ .deadlock_handler(|| {
+ // 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)
+ .try_collect_active_jobs()
+ .expect("active jobs shouldn't be locked in deadlock handler")
+ });
+ let registry = rustc_rayon_core::Registry::current();
+ thread::spawn(move || deadlock(query_map, &registry));
+ });
if let Some(size) = get_stack_size() {
- config = config.stack_size(size);
+ builder = builder.stack_size(size);
}
- let with_pool = move |pool: &rayon::ThreadPool| pool.install(f);
-
+ // We create the session globals on the main thread, then create the thread
+ // pool. Upon creation, each worker thread created gets a copy of the
+ // session globals in TLS. This is possible because `SessionGlobals` impls
+ // `Send` in the parallel compiler.
rustc_span::create_session_globals_then(edition, || {
rustc_span::with_session_globals(|session_globals| {
- // The main handler runs for each Rayon worker thread and sets up
- // the thread local rustc uses. `session_globals` is captured and set
- // on the new threads.
- let main_handler = move |thread: rayon::ThreadBuilder| {
- rustc_span::set_session_globals_then(session_globals, || thread.run())
- };
-
- config.build_scoped(main_handler, with_pool).unwrap()
+ builder
+ .build_scoped(
+ // Initialize each new worker thread when created.
+ move |thread: rayon::ThreadBuilder| {
+ rustc_span::set_session_globals_then(session_globals, || thread.run())
+ },
+ // Run `f` on the first thread in the thread pool.
+ move |pool: &rayon::ThreadPool| pool.install(f),
+ )
+ .unwrap()
})
})
}
diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml
index 35af11053..ad685c2ad 100644
--- a/compiler/rustc_lexer/Cargo.toml
+++ b/compiler/rustc_lexer/Cargo.toml
@@ -12,7 +12,6 @@ Rust lexer used by rustc. No stability guarantees are provided.
# Note: do not remove this blank `[lib]` section.
# This will be used when publishing this crate as `rustc-ap-rustc_lexer`.
[lib]
-doctest = false
# Note that this crate purposefully does not depend on other rustc crates
[dependencies]
diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs
index 21557a9c8..eceef5980 100644
--- a/compiler/rustc_lexer/src/cursor.rs
+++ b/compiler/rustc_lexer/src/cursor.rs
@@ -4,8 +4,8 @@ use std::str::Chars;
///
/// Next characters can be peeked via `first` method,
/// and position can be shifted forward via `bump` method.
-pub(crate) struct Cursor<'a> {
- initial_len: usize,
+pub struct Cursor<'a> {
+ len_remaining: usize,
/// Iterator over chars. Slightly faster than a &str.
chars: Chars<'a>,
#[cfg(debug_assertions)]
@@ -15,9 +15,9 @@ pub(crate) struct Cursor<'a> {
pub(crate) const EOF_CHAR: char = '\0';
impl<'a> Cursor<'a> {
- pub(crate) fn new(input: &'a str) -> Cursor<'a> {
+ pub fn new(input: &'a str) -> Cursor<'a> {
Cursor {
- initial_len: input.len(),
+ len_remaining: input.len(),
chars: input.chars(),
#[cfg(debug_assertions)]
prev: EOF_CHAR,
@@ -61,13 +61,13 @@ impl<'a> Cursor<'a> {
}
/// Returns amount of already consumed symbols.
- pub(crate) fn len_consumed(&self) -> u32 {
- (self.initial_len - self.chars.as_str().len()) as u32
+ pub(crate) fn pos_within_token(&self) -> u32 {
+ (self.len_remaining - self.chars.as_str().len()) as u32
}
/// Resets the number of bytes consumed to 0.
- pub(crate) fn reset_len_consumed(&mut self) {
- self.initial_len = self.chars.as_str().len();
+ pub(crate) fn reset_pos_within_token(&mut self) {
+ self.len_remaining = self.chars.as_str().len();
}
/// Moves to the next character.
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index a79c98264..51515976e 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -29,9 +29,11 @@ pub mod unescape;
#[cfg(test)]
mod tests;
+pub use crate::cursor::Cursor;
+
use self::LiteralKind::*;
use self::TokenKind::*;
-use crate::cursor::{Cursor, EOF_CHAR};
+use crate::cursor::EOF_CHAR;
use std::convert::TryFrom;
/// Parsed token.
@@ -55,29 +57,42 @@ pub enum TokenKind {
// Multi-char tokens:
/// "// comment"
LineComment { doc_style: Option<DocStyle> },
+
/// `/* block comment */`
///
- /// Block comments can be recursive, so the sequence like `/* /* */`
+ /// Block comments can be recursive, so a sequence like `/* /* */`
/// will not be considered terminated and will result in a parsing error.
BlockComment { doc_style: Option<DocStyle>, terminated: bool },
- /// Any whitespace characters sequence.
+
+ /// Any whitespace character sequence.
Whitespace,
+
/// "ident" or "continue"
- /// At this step keywords are also considered identifiers.
+ ///
+ /// At this step, keywords are also considered identifiers.
Ident,
+
/// Like the above, but containing invalid unicode codepoints.
InvalidIdent,
+
/// "r#ident"
RawIdent,
- /// An unknown prefix like `foo#`, `foo'`, `foo"`. Note that only the
+
+ /// An unknown prefix, like `foo#`, `foo'`, `foo"`.
+ ///
+ /// Note that only the
/// prefix (`foo`) is included in the token, not the separator (which is
/// lexed as its own distinct token). In Rust 2021 and later, reserved
/// prefixes are reported as errors; in earlier editions, they result in a
/// (allowed by default) lint, and are treated as regular identifier
/// tokens.
UnknownPrefix,
- /// "12_u8", "1.0e-40", "b"123"". See `LiteralKind` for more details.
+
+ /// Examples: `"12_u8"`, `"1.0e-40"`, `b"123`.
+ ///
+ /// See [LiteralKind] for more details.
Literal { kind: LiteralKind, suffix_start: u32 },
+
/// "'a"
Lifetime { starts_with_number: bool },
@@ -139,6 +154,9 @@ pub enum TokenKind {
/// Unknown token, not expected by the lexer, e.g. "№"
Unknown,
+
+ /// End of input.
+ Eof,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -219,13 +237,6 @@ pub fn strip_shebang(input: &str) -> Option<usize> {
None
}
-/// Parses the first token from the provided input string.
-#[inline]
-pub fn first_token(input: &str) -> Token {
- debug_assert!(!input.is_empty());
- Cursor::new(input).advance_token()
-}
-
/// Validates a raw string literal. Used for getting more information about a
/// problem with a `RawStr`/`RawByteStr` with a `None` field.
#[inline]
@@ -243,12 +254,8 @@ pub fn validate_raw_str(input: &str, prefix_len: u32) -> Result<(), RawStrError>
pub fn tokenize(input: &str) -> impl Iterator<Item = Token> + '_ {
let mut cursor = Cursor::new(input);
std::iter::from_fn(move || {
- if cursor.is_eof() {
- None
- } else {
- cursor.reset_len_consumed();
- Some(cursor.advance_token())
- }
+ let token = cursor.advance_token();
+ if token.kind != TokenKind::Eof { Some(token) } else { None }
})
}
@@ -311,8 +318,11 @@ pub fn is_ident(string: &str) -> bool {
impl Cursor<'_> {
/// Parses a token from the input string.
- fn advance_token(&mut self) -> Token {
- let first_char = self.bump().unwrap();
+ pub fn advance_token(&mut self) -> Token {
+ let first_char = match self.bump() {
+ Some(c) => c,
+ None => return Token::new(TokenKind::Eof, 0),
+ };
let token_kind = match first_char {
// Slash, comment or block comment.
'/' => match self.first() {
@@ -329,7 +339,7 @@ impl Cursor<'_> {
('#', c1) if is_id_start(c1) => self.raw_ident(),
('#', _) | ('"', _) => {
let res = self.raw_double_quoted_string(1);
- let suffix_start = self.len_consumed();
+ let suffix_start = self.pos_within_token();
if res.is_ok() {
self.eat_literal_suffix();
}
@@ -344,7 +354,7 @@ impl Cursor<'_> {
('\'', _) => {
self.bump();
let terminated = self.single_quoted_string();
- let suffix_start = self.len_consumed();
+ let suffix_start = self.pos_within_token();
if terminated {
self.eat_literal_suffix();
}
@@ -354,7 +364,7 @@ impl Cursor<'_> {
('"', _) => {
self.bump();
let terminated = self.double_quoted_string();
- let suffix_start = self.len_consumed();
+ let suffix_start = self.pos_within_token();
if terminated {
self.eat_literal_suffix();
}
@@ -364,7 +374,7 @@ impl Cursor<'_> {
('r', '"') | ('r', '#') => {
self.bump();
let res = self.raw_double_quoted_string(2);
- let suffix_start = self.len_consumed();
+ let suffix_start = self.pos_within_token();
if res.is_ok() {
self.eat_literal_suffix();
}
@@ -381,7 +391,7 @@ impl Cursor<'_> {
// Numeric literal.
c @ '0'..='9' => {
let literal_kind = self.number(c);
- let suffix_start = self.len_consumed();
+ let suffix_start = self.pos_within_token();
self.eat_literal_suffix();
TokenKind::Literal { kind: literal_kind, suffix_start }
}
@@ -420,7 +430,7 @@ impl Cursor<'_> {
// String literal.
'"' => {
let terminated = self.double_quoted_string();
- let suffix_start = self.len_consumed();
+ let suffix_start = self.pos_within_token();
if terminated {
self.eat_literal_suffix();
}
@@ -433,7 +443,9 @@ impl Cursor<'_> {
}
_ => Unknown,
};
- Token::new(token_kind, self.len_consumed())
+ let res = Token::new(token_kind, self.pos_within_token());
+ self.reset_pos_within_token();
+ res
}
fn line_comment(&mut self) -> TokenKind {
@@ -618,7 +630,7 @@ impl Cursor<'_> {
if !can_be_a_lifetime {
let terminated = self.single_quoted_string();
- let suffix_start = self.len_consumed();
+ let suffix_start = self.pos_within_token();
if terminated {
self.eat_literal_suffix();
}
@@ -643,7 +655,7 @@ impl Cursor<'_> {
if self.first() == '\'' {
self.bump();
let kind = Char { terminated: true };
- Literal { kind, suffix_start: self.len_consumed() }
+ Literal { kind, suffix_start: self.pos_within_token() }
} else {
Lifetime { starts_with_number }
}
@@ -724,7 +736,7 @@ impl Cursor<'_> {
fn raw_string_unvalidated(&mut self, prefix_len: u32) -> Result<u32, RawStrError> {
debug_assert!(self.prev() == 'r');
- let start_pos = self.len_consumed();
+ let start_pos = self.pos_within_token();
let mut possible_terminator_offset = None;
let mut max_hashes = 0;
@@ -778,7 +790,7 @@ impl Cursor<'_> {
// Keep track of possible terminators to give a hint about
// where there might be a missing terminator
possible_terminator_offset =
- Some(self.len_consumed() - start_pos - n_end_hashes + prefix_len);
+ Some(self.pos_within_token() - start_pos - n_end_hashes + prefix_len);
max_hashes = n_end_hashes;
}
}
diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs
index 3da6bc146..8f64b5f51 100644
--- a/compiler/rustc_lexer/src/unescape.rs
+++ b/compiler/rustc_lexer/src/unescape.rs
@@ -93,7 +93,7 @@ where
// NOTE: Raw strings do not perform any explicit character escaping, here we
// only translate CRLF to LF and produce errors on bare CR.
Mode::RawStr | Mode::RawByteStr => {
- unescape_raw_str_or_byte_str(literal_text, mode, callback)
+ unescape_raw_str_or_raw_byte_str(literal_text, mode, callback)
}
}
}
@@ -105,7 +105,7 @@ pub fn unescape_byte_literal<F>(literal_text: &str, mode: Mode, callback: &mut F
where
F: FnMut(Range<usize>, Result<u8, EscapeError>),
{
- assert!(mode.is_bytes());
+ debug_assert!(mode.is_bytes());
unescape_literal(literal_text, mode, &mut |range, result| {
callback(range, result.map(byte_from_char));
})
@@ -129,7 +129,7 @@ pub fn unescape_byte(literal_text: &str) -> Result<u8, (usize, EscapeError)> {
}
/// What kind of literal do we parse.
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Mode {
Char,
Str,
@@ -140,17 +140,13 @@ pub enum Mode {
}
impl Mode {
- pub fn in_single_quotes(self) -> bool {
+ pub fn in_double_quotes(self) -> bool {
match self {
- Mode::Char | Mode::Byte => true,
- Mode::Str | Mode::ByteStr | Mode::RawStr | Mode::RawByteStr => false,
+ Mode::Str | Mode::ByteStr | Mode::RawStr | Mode::RawByteStr => true,
+ Mode::Char | Mode::Byte => false,
}
}
- pub fn in_double_quotes(self) -> bool {
- !self.in_single_quotes()
- }
-
pub fn is_bytes(self) -> bool {
match self {
Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
@@ -184,7 +180,7 @@ fn scan_escape(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
let value = hi * 16 + lo;
- // For a byte literal verify that it is within ASCII range.
+ // For a non-byte literal verify that it is within ASCII range.
if !mode.is_bytes() && !is_ascii(value) {
return Err(EscapeError::OutOfRangeHexEscape);
}
@@ -263,6 +259,7 @@ fn ascii_check(first_char: char, mode: Mode) -> Result<char, EscapeError> {
}
fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
+ debug_assert!(mode == Mode::Char || mode == Mode::Byte);
let first_char = chars.next().ok_or(EscapeError::ZeroChars)?;
let res = match first_char {
'\\' => scan_escape(chars, mode),
@@ -282,7 +279,7 @@ fn unescape_str_or_byte_str<F>(src: &str, mode: Mode, callback: &mut F)
where
F: FnMut(Range<usize>, Result<char, EscapeError>),
{
- assert!(mode.in_double_quotes());
+ debug_assert!(mode == Mode::Str || mode == Mode::ByteStr);
let initial_len = src.len();
let mut chars = src.chars();
while let Some(first_char) = chars.next() {
@@ -344,11 +341,11 @@ where
/// sequence of characters or errors.
/// NOTE: Raw strings do not perform any explicit character escaping, here we
/// only translate CRLF to LF and produce errors on bare CR.
-fn unescape_raw_str_or_byte_str<F>(literal_text: &str, mode: Mode, callback: &mut F)
+fn unescape_raw_str_or_raw_byte_str<F>(literal_text: &str, mode: Mode, callback: &mut F)
where
F: FnMut(Range<usize>, Result<char, EscapeError>),
{
- assert!(mode.in_double_quotes());
+ debug_assert!(mode == Mode::RawStr || mode == Mode::RawByteStr);
let initial_len = literal_text.len();
let mut chars = literal_text.chars();
@@ -368,7 +365,7 @@ where
fn byte_from_char(c: char) -> u8 {
let res = c as u32;
- assert!(res <= u8::MAX as u32, "guaranteed because of Mode::ByteStr");
+ debug_assert!(res <= u8::MAX as u32, "guaranteed because of Mode::ByteStr");
res as u8
}
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index 7c0f2c440..abe61406c 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
[dependencies]
tracing = "0.1"
-unicode-security = "0.0.5"
+unicode-security = "0.1.0"
rustc_middle = { path = "../rustc_middle" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_attr = { path = "../rustc_attr" }
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index b97f8acb3..abebc533c 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -118,37 +118,41 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
// to an array or to a slice.
_ => bug!("array type coerced to something other than array or slice"),
};
- cx.struct_span_lint(ARRAY_INTO_ITER, call.ident.span, |lint| {
- let mut diag = lint.build(fluent::lint::array_into_iter);
- diag.set_arg("target", target);
- diag.span_suggestion(
- call.ident.span,
- fluent::lint::use_iter_suggestion,
- "iter",
- Applicability::MachineApplicable,
- );
- if self.for_expr_span == expr.span {
+ cx.struct_span_lint(
+ ARRAY_INTO_ITER,
+ call.ident.span,
+ fluent::lint_array_into_iter,
+ |diag| {
+ diag.set_arg("target", target);
diag.span_suggestion(
- receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
- fluent::lint::remove_into_iter_suggestion,
- "",
- Applicability::MaybeIncorrect,
+ call.ident.span,
+ fluent::use_iter_suggestion,
+ "iter",
+ Applicability::MachineApplicable,
);
- } else if receiver_ty.is_array() {
- diag.multipart_suggestion(
- fluent::lint::use_explicit_into_iter_suggestion,
- vec![
- (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
- (
- receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
- ")".into(),
- ),
- ],
- Applicability::MaybeIncorrect,
- );
- }
- diag.emit();
- })
+ if self.for_expr_span == expr.span {
+ diag.span_suggestion(
+ receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
+ fluent::remove_into_iter_suggestion,
+ "",
+ Applicability::MaybeIncorrect,
+ );
+ } else if receiver_ty.is_array() {
+ diag.multipart_suggestion(
+ fluent::use_explicit_into_iter_suggestion,
+ vec![
+ (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
+ (
+ receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
+ ")".into(),
+ ),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ diag
+ },
+ )
}
}
}
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 0ff2ef5cd..d425adf47 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -33,8 +33,8 @@ use rustc_ast_pretty::pprust::{self, expr_to_string};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{
- fluent, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
- LintDiagnosticBuilder, MultiSpan,
+ fluent, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, DiagnosticMessage,
+ DiagnosticStyledString, MultiSpan,
};
use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
use rustc_hir as hir;
@@ -46,8 +46,7 @@ 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::Instance;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
use rustc_span::edition::Edition;
use rustc_span::source_map::Spanned;
@@ -98,30 +97,31 @@ fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
impl EarlyLintPass for WhileTrue {
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
- if let ast::ExprKind::While(cond, _, label) = &e.kind {
- if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind {
- if let ast::LitKind::Bool(true) = lit.kind {
- if !lit.span.from_expansion() {
- let condition_span = e.span.with_hi(cond.span.hi());
- cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
- lint.build(fluent::lint::builtin_while_true)
- .span_suggestion_short(
- condition_span,
- fluent::lint::suggestion,
- format!(
- "{}loop",
- label.map_or_else(String::new, |label| format!(
- "{}: ",
- label.ident,
- ))
- ),
- Applicability::MachineApplicable,
- )
- .emit();
- })
- }
- }
- }
+ if let ast::ExprKind::While(cond, _, label) = &e.kind
+ && let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind
+ && let ast::LitKind::Bool(true) = lit.kind
+ && !lit.span.from_expansion()
+ {
+ let condition_span = e.span.with_hi(cond.span.hi());
+ cx.struct_span_lint(
+ WHILE_TRUE,
+ condition_span,
+ fluent::lint_builtin_while_true,
+ |lint| {
+ lint.span_suggestion_short(
+ condition_span,
+ fluent::suggestion,
+ format!(
+ "{}loop",
+ label.map_or_else(String::new, |label| format!(
+ "{}: ",
+ label.ident,
+ ))
+ ),
+ Applicability::MachineApplicable,
+ )
+ },
+ )
}
}
}
@@ -157,9 +157,12 @@ impl BoxPointers {
for leaf in ty.walk() {
if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
if leaf_ty.is_box() {
- cx.struct_span_lint(BOX_POINTERS, span, |lint| {
- lint.build(fluent::lint::builtin_box_pointers).set_arg("ty", ty).emit();
- });
+ cx.struct_span_lint(
+ BOX_POINTERS,
+ span,
+ fluent::lint_builtin_box_pointers,
+ |lint| lint.set_arg("ty", ty),
+ );
}
}
}
@@ -174,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxPointers {
| hir::ItemKind::Enum(..)
| hir::ItemKind::Struct(..)
| hir::ItemKind::Union(..) => {
- self.check_heap_type(cx, it.span, cx.tcx.type_of(it.def_id))
+ self.check_heap_type(cx, it.span, cx.tcx.type_of(it.owner_id))
}
_ => (),
}
@@ -258,19 +261,21 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
if cx.tcx.find_field_index(ident, &variant)
== Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results()))
{
- cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| {
- let suggested_ident =
- format!("{}{}", binding_annot.prefix_str(), ident);
- lint.build(fluent::lint::builtin_non_shorthand_field_patterns)
- .set_arg("ident", ident.clone())
- .span_suggestion(
+ cx.struct_span_lint(
+ NON_SHORTHAND_FIELD_PATTERNS,
+ fieldpat.span,
+ fluent::lint_builtin_non_shorthand_field_patterns,
+ |lint| {
+ let suggested_ident =
+ format!("{}{}", binding_annot.prefix_str(), ident);
+ lint.set_arg("ident", ident.clone()).span_suggestion(
fieldpat.span,
- fluent::lint::suggestion,
+ fluent::suggestion,
suggested_ident,
Applicability::MachineApplicable,
)
- .emit();
- });
+ },
+ );
}
}
}
@@ -310,14 +315,17 @@ impl UnsafeCode {
&self,
cx: &EarlyContext<'_>,
span: Span,
- decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+ msg: impl Into<DiagnosticMessage>,
+ decorate: impl for<'a, 'b> FnOnce(
+ &'b mut DiagnosticBuilder<'a, ()>,
+ ) -> &'b mut DiagnosticBuilder<'a, ()>,
) {
// This comes from a macro that has `#[allow_internal_unsafe]`.
if span.allows_unsafe() {
return;
}
- cx.struct_span_lint(UNSAFE_CODE, span, decorate);
+ cx.struct_span_lint(UNSAFE_CODE, span, msg, decorate);
}
fn report_overridden_symbol_name(
@@ -326,8 +334,8 @@ impl UnsafeCode {
span: Span,
msg: DiagnosticMessage,
) {
- self.report_unsafe(cx, span, |lint| {
- lint.build(msg).note(fluent::lint::builtin_overridden_symbol_name).emit();
+ self.report_unsafe(cx, span, msg, |lint| {
+ lint.note(fluent::lint_builtin_overridden_symbol_name)
})
}
@@ -337,8 +345,8 @@ impl UnsafeCode {
span: Span,
msg: DiagnosticMessage,
) {
- self.report_unsafe(cx, span, |lint| {
- lint.build(msg).note(fluent::lint::builtin_overridden_symbol_section).emit();
+ self.report_unsafe(cx, span, msg, |lint| {
+ lint.note(fluent::lint_builtin_overridden_symbol_section)
})
}
}
@@ -346,8 +354,8 @@ impl UnsafeCode {
impl EarlyLintPass for UnsafeCode {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
if attr.has_name(sym::allow_internal_unsafe) {
- self.report_unsafe(cx, attr.span, |lint| {
- lint.build(fluent::lint::builtin_allow_internal_unsafe).emit();
+ self.report_unsafe(cx, attr.span, fluent::lint_builtin_allow_internal_unsafe, |lint| {
+ lint
});
}
}
@@ -356,31 +364,27 @@ impl EarlyLintPass for UnsafeCode {
if let ast::ExprKind::Block(ref blk, _) = e.kind {
// Don't warn about generated blocks; that'll just pollute the output.
if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
- self.report_unsafe(cx, blk.span, |lint| {
- lint.build(fluent::lint::builtin_unsafe_block).emit();
- });
+ self.report_unsafe(cx, blk.span, fluent::lint_builtin_unsafe_block, |lint| lint);
}
}
}
fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
match it.kind {
- ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => self
- .report_unsafe(cx, it.span, |lint| {
- lint.build(fluent::lint::builtin_unsafe_trait).emit();
- }),
+ ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => {
+ self.report_unsafe(cx, it.span, fluent::lint_builtin_unsafe_trait, |lint| lint)
+ }
- ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => self
- .report_unsafe(cx, it.span, |lint| {
- lint.build(fluent::lint::builtin_unsafe_impl).emit();
- }),
+ ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => {
+ self.report_unsafe(cx, it.span, fluent::lint_builtin_unsafe_impl, |lint| lint)
+ }
ast::ItemKind::Fn(..) => {
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
self.report_overridden_symbol_name(
cx,
attr.span,
- fluent::lint::builtin_no_mangle_fn,
+ fluent::lint_builtin_no_mangle_fn,
);
}
@@ -388,7 +392,7 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_name(
cx,
attr.span,
- fluent::lint::builtin_export_name_fn,
+ fluent::lint_builtin_export_name_fn,
);
}
@@ -396,7 +400,7 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_section(
cx,
attr.span,
- fluent::lint::builtin_link_section_fn,
+ fluent::lint_builtin_link_section_fn,
);
}
}
@@ -406,7 +410,7 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_name(
cx,
attr.span,
- fluent::lint::builtin_no_mangle_static,
+ fluent::lint_builtin_no_mangle_static,
);
}
@@ -414,7 +418,7 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_name(
cx,
attr.span,
- fluent::lint::builtin_export_name_static,
+ fluent::lint_builtin_export_name_static,
);
}
@@ -422,7 +426,7 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_section(
cx,
attr.span,
- fluent::lint::builtin_link_section_static,
+ fluent::lint_builtin_link_section_static,
);
}
}
@@ -437,14 +441,14 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_name(
cx,
attr.span,
- fluent::lint::builtin_no_mangle_method,
+ fluent::lint_builtin_no_mangle_method,
);
}
if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
self.report_overridden_symbol_name(
cx,
attr.span,
- fluent::lint::builtin_export_name_method,
+ fluent::lint_builtin_export_name_method,
);
}
}
@@ -462,13 +466,11 @@ impl EarlyLintPass for UnsafeCode {
{
let msg = match ctxt {
FnCtxt::Foreign => return,
- FnCtxt::Free => fluent::lint::builtin_decl_unsafe_fn,
- FnCtxt::Assoc(_) if body.is_none() => fluent::lint::builtin_decl_unsafe_method,
- FnCtxt::Assoc(_) => fluent::lint::builtin_impl_unsafe_method,
+ FnCtxt::Free => fluent::lint_builtin_decl_unsafe_fn,
+ FnCtxt::Assoc(_) if body.is_none() => fluent::lint_builtin_decl_unsafe_method,
+ FnCtxt::Assoc(_) => fluent::lint_builtin_impl_unsafe_method,
};
- self.report_unsafe(cx, span, |lint| {
- lint.build(msg).emit();
- });
+ self.report_unsafe(cx, span, msg, |lint| lint);
}
}
}
@@ -561,7 +563,7 @@ impl MissingDoc {
// It's an option so the crate root can also use this function (it doesn't
// have a `NodeId`).
if def_id != CRATE_DEF_ID {
- if !cx.access_levels.is_exported(def_id) {
+ if !cx.effective_visibilities.is_exported(def_id) {
return;
}
}
@@ -569,12 +571,12 @@ impl MissingDoc {
let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id));
let has_doc = attrs.iter().any(has_doc);
if !has_doc {
- cx.struct_span_lint(MISSING_DOCS, cx.tcx.def_span(def_id), |lint| {
- lint.build(fluent::lint::builtin_missing_doc)
- .set_arg("article", article)
- .set_arg("desc", desc)
- .emit();
- });
+ cx.struct_span_lint(
+ MISSING_DOCS,
+ cx.tcx.def_span(def_id),
+ fluent::lint_builtin_missing_doc,
+ |lint| lint.set_arg("article", article).set_arg("desc", desc),
+ );
}
}
}
@@ -604,9 +606,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
match it.kind {
hir::ItemKind::Trait(..) => {
// Issue #11592: traits are always considered exported, even when private.
- if cx.tcx.visibility(it.def_id)
+ if cx.tcx.visibility(it.owner_id)
== ty::Visibility::Restricted(
- cx.tcx.parent_module_from_def_id(it.def_id).to_def_id(),
+ cx.tcx.parent_module_from_def_id(it.owner_id.def_id).to_def_id(),
)
{
return;
@@ -625,15 +627,15 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
_ => return,
};
- let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
+ let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());
- self.check_missing_docs_attrs(cx, it.def_id, article, desc);
+ self.check_missing_docs_attrs(cx, it.owner_id.def_id, article, desc);
}
fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) {
- let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
+ let (article, desc) = cx.tcx.article_and_description(trait_item.owner_id.to_def_id());
- self.check_missing_docs_attrs(cx, trait_item.def_id, article, desc);
+ self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, article, desc);
}
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
@@ -660,13 +662,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
}
}
- let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
- self.check_missing_docs_attrs(cx, impl_item.def_id, article, desc);
+ let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
+ self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, article, desc);
}
fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) {
- let (article, desc) = cx.tcx.article_and_description(foreign_item.def_id.to_def_id());
- self.check_missing_docs_attrs(cx, foreign_item.def_id, article, desc);
+ let (article, desc) = cx.tcx.article_and_description(foreign_item.owner_id.to_def_id());
+ self.check_missing_docs_attrs(cx, foreign_item.owner_id.def_id, article, desc);
}
fn check_field_def(&mut self, cx: &LateContext<'_>, sf: &hir::FieldDef<'_>) {
@@ -719,7 +721,7 @@ 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.access_levels.is_reachable(item.def_id) {
+ if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
return;
}
let (def, ty) = match item.kind {
@@ -727,21 +729,21 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
if !ast_generics.params.is_empty() {
return;
}
- let def = cx.tcx.adt_def(item.def_id);
+ let def = cx.tcx.adt_def(item.owner_id);
(def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
}
hir::ItemKind::Union(_, ref ast_generics) => {
if !ast_generics.params.is_empty() {
return;
}
- let def = cx.tcx.adt_def(item.def_id);
+ let def = cx.tcx.adt_def(item.owner_id);
(def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
}
hir::ItemKind::Enum(_, ref ast_generics) => {
if !ast_generics.params.is_empty() {
return;
}
- let def = cx.tcx.adt_def(item.def_id);
+ let def = cx.tcx.adt_def(item.owner_id);
(def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
}
_ => return,
@@ -750,7 +752,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
return;
}
let param_env = ty::ParamEnv::empty();
- if ty.is_copy_modulo_regions(cx.tcx.at(item.span), param_env) {
+ if ty.is_copy_modulo_regions(cx.tcx, param_env) {
return;
}
if can_type_implement_copy(
@@ -761,9 +763,12 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
)
.is_ok()
{
- cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| {
- lint.build(fluent::lint::builtin_missing_copy_impl).emit();
- })
+ cx.struct_span_lint(
+ MISSING_COPY_IMPLEMENTATIONS,
+ item.span,
+ fluent::lint_builtin_missing_copy_impl,
+ |lint| lint,
+ )
}
}
}
@@ -809,7 +814,7 @@ 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.access_levels.is_reachable(item.def_id) {
+ if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
return;
}
@@ -836,12 +841,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
debug!("{:?}", self.impling_types);
}
- if !self.impling_types.as_ref().unwrap().contains(&item.def_id) {
- cx.struct_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, |lint| {
- lint.build(fluent::lint::builtin_missing_debug_impl)
- .set_arg("debug", cx.tcx.def_path_str(debug))
- .emit();
- });
+ if !self.impling_types.as_ref().unwrap().contains(&item.owner_id.def_id) {
+ cx.struct_span_lint(
+ MISSING_DEBUG_IMPLEMENTATIONS,
+ item.span,
+ fluent::lint_builtin_missing_debug_impl,
+ |lint| lint.set_arg("debug", cx.tcx.def_path_str(debug)),
+ );
}
}
}
@@ -909,24 +915,26 @@ impl EarlyLintPass for AnonymousParameters {
for arg in sig.decl.inputs.iter() {
if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
if ident.name == kw::Empty {
- cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| {
- let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
-
- let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
- (snip.as_str(), Applicability::MachineApplicable)
- } else {
- ("<type>", Applicability::HasPlaceholders)
- };
+ let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
- lint.build(fluent::lint::builtin_anonymous_params)
- .span_suggestion(
+ let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
+ (snip.as_str(), Applicability::MachineApplicable)
+ } else {
+ ("<type>", Applicability::HasPlaceholders)
+ };
+ cx.struct_span_lint(
+ ANONYMOUS_PARAMETERS,
+ arg.pat.span,
+ fluent::lint_builtin_anonymous_params,
+ |lint| {
+ lint.span_suggestion(
arg.pat.span,
- fluent::lint::suggestion,
+ fluent::suggestion,
format!("_: {}", ty_snip),
appl,
)
- .emit();
- })
+ },
+ )
}
}
}
@@ -961,38 +969,44 @@ impl EarlyLintPass for DeprecatedAttr {
_,
) = gate
{
- cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
- // FIXME(davidtwco) translatable deprecated attr
- lint.build(fluent::lint::builtin_deprecated_attr_link)
- .set_arg("name", name)
- .set_arg("reason", reason)
- .set_arg("link", link)
- .span_suggestion_short(
- attr.span,
- suggestion.map(|s| s.into()).unwrap_or(
- fluent::lint::builtin_deprecated_attr_default_suggestion,
- ),
- "",
- Applicability::MachineApplicable,
- )
- .emit();
- });
+ // FIXME(davidtwco) translatable deprecated attr
+ cx.struct_span_lint(
+ DEPRECATED,
+ attr.span,
+ fluent::lint_builtin_deprecated_attr_link,
+ |lint| {
+ lint.set_arg("name", name)
+ .set_arg("reason", reason)
+ .set_arg("link", link)
+ .span_suggestion_short(
+ attr.span,
+ suggestion.map(|s| s.into()).unwrap_or(
+ fluent::lint_builtin_deprecated_attr_default_suggestion,
+ ),
+ "",
+ Applicability::MachineApplicable,
+ )
+ },
+ );
}
return;
}
}
if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) {
- cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
- lint.build(fluent::lint::builtin_deprecated_attr_used)
- .set_arg("name", pprust::path_to_string(&attr.get_normal_item().path))
- .span_suggestion_short(
- attr.span,
- fluent::lint::builtin_deprecated_attr_default_suggestion,
- "",
- Applicability::MachineApplicable,
- )
- .emit();
- });
+ cx.struct_span_lint(
+ DEPRECATED,
+ attr.span,
+ fluent::lint_builtin_deprecated_attr_used,
+ |lint| {
+ lint.set_arg("name", pprust::path_to_string(&attr.get_normal_item().path))
+ .span_suggestion_short(
+ attr.span,
+ fluent::lint_builtin_deprecated_attr_default_suggestion,
+ "",
+ Applicability::MachineApplicable,
+ )
+ },
+ );
}
}
}
@@ -1019,20 +1033,21 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &
let span = sugared_span.take().unwrap_or(attr.span);
if is_doc_comment || attr.has_name(sym::doc) {
- cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
- let mut err = lint.build(fluent::lint::builtin_unused_doc_comment);
- err.set_arg("kind", node_kind);
- err.span_label(node_span, fluent::lint::label);
- match attr.kind {
- AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
- err.help(fluent::lint::plain_help);
- }
- AttrKind::DocComment(CommentKind::Block, _) => {
- err.help(fluent::lint::block_help);
- }
- }
- err.emit();
- });
+ cx.struct_span_lint(
+ UNUSED_DOC_COMMENTS,
+ span,
+ fluent::lint_builtin_unused_doc_comment,
+ |lint| {
+ lint.set_arg("kind", node_kind).span_label(node_span, fluent::label).help(
+ match attr.kind {
+ AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
+ fluent::plain_help
+ }
+ AttrKind::DocComment(CommentKind::Block, _) => fluent::block_help,
+ },
+ )
+ },
+ );
}
}
}
@@ -1146,18 +1161,21 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
match param.kind {
GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
- cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, span, |lint| {
- lint.build(fluent::lint::builtin_no_mangle_generic)
- .span_suggestion_short(
+ cx.struct_span_lint(
+ NO_MANGLE_GENERIC_ITEMS,
+ span,
+ fluent::lint_builtin_no_mangle_generic,
+ |lint| {
+ lint.span_suggestion_short(
no_mangle_attr.span,
- fluent::lint::suggestion,
+ fluent::suggestion,
"",
// Use of `#[no_mangle]` suggests FFI intent; correct
// fix may be to monomorphize source by hand
Applicability::MaybeIncorrect,
)
- .emit();
- });
+ },
+ );
break;
}
}
@@ -1173,27 +1191,29 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
if cx.sess().contains_name(attrs, sym::no_mangle) {
// Const items do not refer to a particular location in memory, and therefore
// don't have anything to attach a symbol to
- cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, |lint| {
- let mut err = lint.build(fluent::lint::builtin_const_no_mangle);
-
- // account for "pub const" (#45562)
- let start = cx
- .tcx
- .sess
- .source_map()
- .span_to_snippet(it.span)
- .map(|snippet| snippet.find("const").unwrap_or(0))
- .unwrap_or(0) as u32;
- // `const` is 5 chars
- let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
- err.span_suggestion(
- const_span,
- fluent::lint::suggestion,
- "pub static",
- Applicability::MachineApplicable,
- );
- err.emit();
- });
+ cx.struct_span_lint(
+ NO_MANGLE_CONST_ITEMS,
+ it.span,
+ fluent::lint_builtin_const_no_mangle,
+ |lint| {
+ // account for "pub const" (#45562)
+ let start = cx
+ .tcx
+ .sess
+ .source_map()
+ .span_to_snippet(it.span)
+ .map(|snippet| snippet.find("const").unwrap_or(0))
+ .unwrap_or(0) as u32;
+ // `const` is 5 chars
+ let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
+ lint.span_suggestion(
+ const_span,
+ fluent::suggestion,
+ "pub static",
+ Applicability::MachineApplicable,
+ )
+ },
+ );
}
}
hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
@@ -1206,7 +1226,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
check_no_mangle_on_generic_fn(
no_mangle_attr,
Some(generics),
- cx.tcx.hir().get_generics(it.id.def_id).unwrap(),
+ cx.tcx.hir().get_generics(it.id.owner_id.def_id).unwrap(),
it.span,
);
}
@@ -1253,9 +1273,12 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
{
if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not {
- cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| {
- lint.build(fluent::lint::builtin_mutable_transmutes).emit();
- });
+ cx.struct_span_lint(
+ MUTABLE_TRANSMUTES,
+ expr.span,
+ fluent::lint_builtin_mutable_transmutes,
+ |lint| lint,
+ );
}
}
@@ -1303,9 +1326,12 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
if attr.has_name(sym::feature) {
if let Some(items) = attr.meta_item_list() {
for item in items {
- cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
- lint.build(fluent::lint::builtin_unstable_features).emit();
- });
+ cx.struct_span_lint(
+ UNSTABLE_FEATURES,
+ item.span(),
+ fluent::lint_builtin_unstable_features,
+ |lint| lint,
+ );
}
}
}
@@ -1359,26 +1385,26 @@ impl UnreachablePub {
exportable: bool,
) {
let mut applicability = Applicability::MachineApplicable;
- if cx.tcx.visibility(def_id).is_public() && !cx.access_levels.is_reachable(def_id) {
+ if cx.tcx.visibility(def_id).is_public() && !cx.effective_visibilities.is_reachable(def_id)
+ {
if vis_span.from_expansion() {
applicability = Applicability::MaybeIncorrect;
}
let def_span = cx.tcx.def_span(def_id);
- cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
- let mut err = lint.build(fluent::lint::builtin_unreachable_pub);
- err.set_arg("what", what);
-
- err.span_suggestion(
- vis_span,
- fluent::lint::suggestion,
- "pub(crate)",
- applicability,
- );
- if exportable {
- err.help(fluent::lint::help);
- }
- err.emit();
- });
+ cx.struct_span_lint(
+ UNREACHABLE_PUB,
+ def_span,
+ fluent::lint_builtin_unreachable_pub,
+ |lint| {
+ lint.set_arg("what", what);
+
+ lint.span_suggestion(vis_span, fluent::suggestion, "pub(crate)", applicability);
+ if exportable {
+ lint.help(fluent::help);
+ }
+ lint
+ },
+ );
}
}
}
@@ -1389,11 +1415,11 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind {
return;
}
- self.perform_lint(cx, "item", item.def_id, item.vis_span, true);
+ self.perform_lint(cx, "item", item.owner_id.def_id, item.vis_span, true);
}
fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
- self.perform_lint(cx, "item", foreign_item.def_id, foreign_item.vis_span, true);
+ self.perform_lint(cx, "item", foreign_item.owner_id.def_id, foreign_item.vis_span, true);
}
fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
@@ -1403,8 +1429,8 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
// Only lint inherent impl items.
- if cx.tcx.associated_item(impl_item.def_id).trait_item_def_id.is_none() {
- self.perform_lint(cx, "item", impl_item.def_id, impl_item.vis_span, false);
+ if cx.tcx.associated_item(impl_item.owner_id).trait_item_def_id.is_none() {
+ self.perform_lint(cx, "item", impl_item.owner_id.def_id, impl_item.vis_span, false);
}
}
}
@@ -1465,7 +1491,7 @@ impl TypeAliasBounds {
impl Visitor<'_> for WalkAssocTypes<'_> {
fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) {
if TypeAliasBounds::is_type_variable_assoc(qpath) {
- self.err.span_help(span, fluent::lint::builtin_type_alias_bounds_help);
+ self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help);
}
intravisit::walk_qpath(self, qpath, id)
}
@@ -1508,36 +1534,34 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
let mut suggested_changing_assoc_types = false;
if !where_spans.is_empty() {
- cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
- let mut err = lint.build(fluent::lint::builtin_type_alias_where_clause);
- err.set_span(where_spans);
- err.span_suggestion(
+ cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_where_clause, |lint| {
+ lint.set_span(where_spans);
+ lint.span_suggestion(
type_alias_generics.where_clause_span,
- fluent::lint::suggestion,
+ fluent::suggestion,
"",
Applicability::MachineApplicable,
);
if !suggested_changing_assoc_types {
- TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
+ TypeAliasBounds::suggest_changing_assoc_types(ty, lint);
suggested_changing_assoc_types = true;
}
- err.emit();
+ lint
});
}
if !inline_spans.is_empty() {
- cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
- let mut err = lint.build(fluent::lint::builtin_type_alias_generic_bounds);
- err.set_span(inline_spans);
- err.multipart_suggestion(
- fluent::lint::suggestion,
+ cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_generic_bounds, |lint| {
+ lint.set_span(inline_spans);
+ lint.multipart_suggestion(
+ fluent::suggestion,
inline_sugg,
Applicability::MachineApplicable,
);
if !suggested_changing_assoc_types {
- TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
+ TypeAliasBounds::suggest_changing_assoc_types(ty, lint);
}
- err.emit();
+ lint
});
}
}
@@ -1615,7 +1639,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
use rustc_middle::ty::PredicateKind::*;
if cx.tcx.features().trivial_bounds {
- let predicates = cx.tcx.predicates_of(item.def_id);
+ let predicates = cx.tcx.predicates_of(item.owner_id);
for &(predicate, span) in predicates.predicates {
let predicate_kind_name = match predicate.kind().skip_binder() {
Trait(..) => "trait",
@@ -1636,12 +1660,15 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
TypeWellFormedFromEnv(..) => continue,
};
if predicate.is_global() {
- cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
- lint.build(fluent::lint::builtin_trivial_bounds)
- .set_arg("predicate_kind_name", predicate_kind_name)
- .set_arg("predicate", predicate)
- .emit();
- });
+ cx.struct_span_lint(
+ TRIVIAL_BOUNDS,
+ span,
+ fluent::lint_builtin_trivial_bounds,
+ |lint| {
+ lint.set_arg("predicate_kind_name", predicate_kind_name)
+ .set_arg("predicate", predicate)
+ },
+ );
}
}
}
@@ -1741,8 +1768,8 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
};
if let Some((start, end, join)) = endpoints {
- let msg = fluent::lint::builtin_ellipsis_inclusive_range_patterns;
- let suggestion = fluent::lint::suggestion;
+ let msg = fluent::lint_builtin_ellipsis_inclusive_range_patterns;
+ let suggestion = fluent::suggestion;
if parenthesise {
self.node_id = Some(pat.id);
let end = expr_to_string(&end);
@@ -1757,15 +1784,13 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
replace,
});
} else {
- cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| {
- lint.build(msg)
- .span_suggestion(
- pat.span,
- suggestion,
- replace,
- Applicability::MachineApplicable,
- )
- .emit();
+ cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, msg, |lint| {
+ lint.span_suggestion(
+ pat.span,
+ suggestion,
+ replace,
+ Applicability::MachineApplicable,
+ )
});
}
} else {
@@ -1777,15 +1802,13 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
replace: replace.to_string(),
});
} else {
- cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| {
- lint.build(msg)
- .span_suggestion_short(
- join,
- suggestion,
- replace,
- Applicability::MachineApplicable,
- )
- .emit();
+ cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, msg, |lint| {
+ lint.span_suggestion_short(
+ join,
+ suggestion,
+ replace,
+ Applicability::MachineApplicable,
+ )
});
}
};
@@ -1841,7 +1864,7 @@ declare_lint! {
}
pub struct UnnameableTestItems {
- boundary: Option<LocalDefId>, // Id of the item under which things are not nameable
+ boundary: Option<hir::OwnerId>, // Id of the item under which things are not nameable
items_nameable: bool,
}
@@ -1859,21 +1882,24 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
if let hir::ItemKind::Mod(..) = it.kind {
} else {
self.items_nameable = false;
- self.boundary = Some(it.def_id);
+ self.boundary = Some(it.owner_id);
}
return;
}
let attrs = cx.tcx.hir().attrs(it.hir_id());
if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) {
- cx.struct_span_lint(UNNAMEABLE_TEST_ITEMS, attr.span, |lint| {
- lint.build(fluent::lint::builtin_unnameable_test_items).emit();
- });
+ cx.struct_span_lint(
+ UNNAMEABLE_TEST_ITEMS,
+ attr.span,
+ fluent::lint_builtin_unnameable_test_items,
+ |lint| lint,
+ );
}
}
fn check_item_post(&mut self, _cx: &LateContext<'_>, it: &hir::Item<'_>) {
- if !self.items_nameable && self.boundary == Some(it.def_id) {
+ if !self.items_nameable && self.boundary == Some(it.owner_id) {
self.items_nameable = true;
}
}
@@ -1984,18 +2010,19 @@ impl KeywordIdents {
return;
}
- cx.struct_span_lint(KEYWORD_IDENTS, ident.span, |lint| {
- lint.build(fluent::lint::builtin_keyword_idents)
- .set_arg("kw", ident.clone())
- .set_arg("next", next_edition)
- .span_suggestion(
+ cx.struct_span_lint(
+ KEYWORD_IDENTS,
+ ident.span,
+ fluent::lint_builtin_keyword_idents,
+ |lint| {
+ lint.set_arg("kw", ident.clone()).set_arg("next", next_edition).span_suggestion(
ident.span,
- fluent::lint::suggestion,
+ fluent::suggestion,
format!("r#{}", ident),
Applicability::MachineApplicable,
)
- .emit();
- });
+ },
+ );
}
}
@@ -2138,7 +2165,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
use rustc_middle::middle::resolve_lifetime::Region;
- let def_id = item.def_id;
+ let def_id = item.owner_id.def_id;
if let hir::ItemKind::Struct(_, ref hir_generics)
| hir::ItemKind::Enum(_, ref hir_generics)
| hir::ItemKind::Union(_, ref hir_generics) = item.kind
@@ -2246,19 +2273,21 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
}
if !lint_spans.is_empty() {
- cx.struct_span_lint(EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), |lint| {
- lint.build(fluent::lint::builtin_explicit_outlives)
- .set_arg("count", bound_count)
- .multipart_suggestion(
- fluent::lint::suggestion,
+ cx.struct_span_lint(
+ EXPLICIT_OUTLIVES_REQUIREMENTS,
+ lint_spans.clone(),
+ fluent::lint_builtin_explicit_outlives,
+ |lint| {
+ lint.set_arg("count", bound_count).multipart_suggestion(
+ fluent::suggestion,
lint_spans
.into_iter()
.map(|span| (span, String::new()))
.collect::<Vec<_>>(),
Applicability::MachineApplicable,
)
- .emit();
- });
+ },
+ );
}
}
}
@@ -2305,18 +2334,24 @@ impl EarlyLintPass for IncompleteFeatures {
.chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
.filter(|(&name, _)| features.incomplete(name))
.for_each(|(&name, &span)| {
- cx.struct_span_lint(INCOMPLETE_FEATURES, span, |lint| {
- let mut builder = lint.build(fluent::lint::builtin_incomplete_features);
- builder.set_arg("name", name);
- if let Some(n) = rustc_feature::find_feature_issue(name, GateIssue::Language) {
- builder.set_arg("n", n);
- builder.note(fluent::lint::note);
- }
- if HAS_MIN_FEATURES.contains(&name) {
- builder.help(fluent::lint::help);
- }
- builder.emit();
- })
+ cx.struct_span_lint(
+ INCOMPLETE_FEATURES,
+ span,
+ fluent::lint_builtin_incomplete_features,
+ |lint| {
+ lint.set_arg("name", name);
+ if let Some(n) =
+ rustc_feature::find_feature_issue(name, GateIssue::Language)
+ {
+ lint.set_arg("n", n);
+ lint.note(fluent::note);
+ }
+ if HAS_MIN_FEATURES.contains(&name) {
+ lint.help(fluent::help);
+ }
+ lint
+ },
+ )
});
}
}
@@ -2425,12 +2460,27 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
None
}
- /// Test if this enum has several actually "existing" variants.
- /// Zero-sized uninhabited variants do not always have a tag assigned and thus do not "exist".
- fn is_multi_variant<'tcx>(adt: ty::AdtDef<'tcx>) -> bool {
- // As an approximation, we only count dataless variants. Those are definitely inhabited.
- let existing_variants = adt.variants().iter().filter(|v| v.fields.is_empty()).count();
- existing_variants > 1
+ fn variant_find_init_error<'tcx>(
+ cx: &LateContext<'tcx>,
+ variant: &VariantDef,
+ substs: ty::SubstsRef<'tcx>,
+ descr: &str,
+ init: InitKind,
+ ) -> Option<InitError> {
+ variant.fields.iter().find_map(|field| {
+ ty_find_init_error(cx, field.ty(cx.tcx, substs), init).map(|(mut msg, span)| {
+ if span.is_none() {
+ // Point to this field, should be helpful for figuring
+ // out where the source of the error is.
+ let span = cx.tcx.def_span(field.did);
+ write!(&mut msg, " (in this {descr})").unwrap();
+ (msg, Some(span))
+ } else {
+ // Just forward.
+ (msg, span)
+ }
+ })
+ })
}
/// Return `Some` only if we are sure this type does *not*
@@ -2468,7 +2518,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
RawPtr(_) if init == InitKind::Uninit => {
Some(("raw pointers must not be uninitialized".to_string(), None))
}
- // Recurse and checks for some compound types.
+ // Recurse and checks for some compound types. (but not unions)
Adt(adt_def, substs) if !adt_def.is_union() => {
// First check if this ADT has a layout attribute (like `NonNull` and friends).
use std::ops::Bound;
@@ -2476,7 +2526,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
// We exploit here that `layout_scalar_valid_range` will never
// return `Bound::Excluded`. (And we have tests checking that we
// handle the attribute correctly.)
- (Bound::Included(lo), _) if lo > 0 => {
+ // We don't add a span since users cannot declare such types anyway.
+ (Bound::Included(lo), Bound::Included(hi)) if 0 < lo && lo < hi => {
+ return Some((format!("`{}` must be non-null", ty), None));
+ }
+ (Bound::Included(lo), Bound::Unbounded) if 0 < lo => {
return Some((format!("`{}` must be non-null", ty), None));
}
(Bound::Included(_), _) | (_, Bound::Included(_))
@@ -2492,50 +2546,65 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
}
_ => {}
}
- // Now, recurse.
- match adt_def.variants().len() {
- 0 => Some(("enums with no variants have no valid value".to_string(), None)),
- 1 => {
- // Struct, or enum with exactly one variant.
- // Proceed recursively, check all fields.
- let variant = &adt_def.variant(VariantIdx::from_u32(0));
- variant.fields.iter().find_map(|field| {
- ty_find_init_error(cx, field.ty(cx.tcx, substs), init).map(
- |(mut msg, span)| {
- if span.is_none() {
- // Point to this field, should be helpful for figuring
- // out where the source of the error is.
- let span = cx.tcx.def_span(field.did);
- write!(
- &mut msg,
- " (in this {} field)",
- adt_def.descr()
- )
- .unwrap();
- (msg, Some(span))
- } else {
- // Just forward.
- (msg, span)
- }
- },
- )
- })
- }
- // Multi-variant enum.
- _ => {
- if init == InitKind::Uninit && is_multi_variant(*adt_def) {
- let span = cx.tcx.def_span(adt_def.did());
- Some((
- "enums have to be initialized to a variant".to_string(),
- Some(span),
- ))
- } else {
- // In principle, for zero-initialization we could figure out which variant corresponds
- // to tag 0, and check that... but for now we just accept all zero-initializations.
- None
- }
+ // Handle structs.
+ if adt_def.is_struct() {
+ return variant_find_init_error(
+ cx,
+ adt_def.non_enum_variant(),
+ substs,
+ "struct field",
+ init,
+ );
+ }
+ // And now, enums.
+ let span = cx.tcx.def_span(adt_def.did());
+ let mut potential_variants = adt_def.variants().iter().filter_map(|variant| {
+ let definitely_inhabited = match variant
+ .inhabited_predicate(cx.tcx, *adt_def)
+ .subst(cx.tcx, substs)
+ .apply_any_module(cx.tcx, cx.param_env)
+ {
+ // Entirely skip uninhbaited variants.
+ Some(false) => return None,
+ // Forward the others, but remember which ones are definitely inhabited.
+ Some(true) => true,
+ None => false,
+ };
+ Some((variant, definitely_inhabited))
+ });
+ let Some(first_variant) = potential_variants.next() else {
+ return Some(("enums with no inhabited variants have no valid value".to_string(), Some(span)));
+ };
+ // So we have at least one potentially inhabited variant. Might we have two?
+ let Some(second_variant) = potential_variants.next() else {
+ // There is only one potentially inhabited variant. So we can recursively check that variant!
+ return variant_find_init_error(
+ cx,
+ &first_variant.0,
+ substs,
+ "field of the only potentially inhabited enum variant",
+ init,
+ );
+ };
+ // So we have at least two potentially inhabited variants.
+ // If we can prove that we have at least two *definitely* inhabited variants,
+ // then we have a tag and hence leaving this uninit is definitely disallowed.
+ // (Leaving it zeroed could be okay, depending on which variant is encoded as zero tag.)
+ if init == InitKind::Uninit {
+ let definitely_inhabited = (first_variant.1 as usize)
+ + (second_variant.1 as usize)
+ + potential_variants
+ .filter(|(_variant, definitely_inhabited)| *definitely_inhabited)
+ .count();
+ if definitely_inhabited > 1 {
+ return Some((
+ "enums with multiple inhabited variants have to be initialized to a variant".to_string(),
+ Some(span),
+ ));
}
}
+ // We couldn't find anything wrong here.
+ None
}
Tuple(..) => {
// Proceed recursively, check all fields.
@@ -2564,28 +2633,37 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init))
{
// FIXME(davidtwco): make translatable
- cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| {
- let mut err = lint.build(&format!(
- "the type `{}` does not permit {}",
- conjured_ty,
- match init {
- InitKind::Zeroed => "zero-initialization",
- InitKind::Uninit => "being left uninitialized",
- },
- ));
- err.span_label(expr.span, "this code causes undefined behavior when executed");
- err.span_label(
- expr.span,
- "help: use `MaybeUninit<T>` instead, \
+ cx.struct_span_lint(
+ INVALID_VALUE,
+ expr.span,
+ DelayDm(|| {
+ format!(
+ "the type `{}` does not permit {}",
+ conjured_ty,
+ match init {
+ InitKind::Zeroed => "zero-initialization",
+ InitKind::Uninit => "being left uninitialized",
+ },
+ )
+ }),
+ |lint| {
+ lint.span_label(
+ expr.span,
+ "this code causes undefined behavior when executed",
+ );
+ lint.span_label(
+ expr.span,
+ "help: use `MaybeUninit<T>` instead, \
and only call `assume_init` after initialization is done",
- );
- if let Some(span) = span {
- err.span_note(span, &msg);
- } else {
- err.note(&msg);
- }
- err.emit();
- });
+ );
+ if let Some(span) = span {
+ lint.span_note(span, &msg);
+ } else {
+ lint.note(&msg);
+ }
+ lint
+ },
+ );
}
}
}
@@ -2666,7 +2744,7 @@ impl ClashingExternDeclarations {
/// Insert a new foreign item into the seen set. If a symbol with the same name already exists
/// for the item, return its HirId without updating the set.
fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> {
- let did = fi.def_id.to_def_id();
+ let did = fi.owner_id.to_def_id();
let instance = Instance::new(did, ty::List::identity_for_item(tcx, did));
let name = Symbol::intern(tcx.symbol_name(instance).name);
if let Some(&hir_id) = self.seen_decls.get(&name) {
@@ -2684,14 +2762,14 @@ impl ClashingExternDeclarations {
/// symbol's name.
fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName {
if let Some((overridden_link_name, overridden_link_name_span)) =
- tcx.codegen_fn_attrs(fi.def_id).link_name.map(|overridden_link_name| {
+ tcx.codegen_fn_attrs(fi.owner_id).link_name.map(|overridden_link_name| {
// FIXME: Instead of searching through the attributes again to get span
// information, we could have codegen_fn_attrs also give span information back for
// where the attribute was defined. However, until this is found to be a
// bottleneck, this does just fine.
(
overridden_link_name,
- tcx.get_attr(fi.def_id.to_def_id(), sym::link_name).unwrap().span,
+ tcx.get_attr(fi.owner_id.to_def_id(), sym::link_name).unwrap().span,
)
})
{
@@ -2908,10 +2986,10 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
let tcx = cx.tcx;
if let Some(existing_hid) = self.insert(tcx, this_fi) {
let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid));
- let this_decl_ty = tcx.type_of(this_fi.def_id);
+ let this_decl_ty = tcx.type_of(this_fi.owner_id);
debug!(
"ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}",
- existing_hid, existing_decl_ty, this_fi.def_id, this_decl_ty
+ existing_hid, existing_decl_ty, this_fi.owner_id, this_decl_ty
);
// Check that the declarations match.
if !Self::structurally_same_type(
@@ -2931,31 +3009,29 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
SymbolName::Link(_, annot_span) => fi.span.to(annot_span),
};
// Finally, emit the diagnostic.
+
+ let msg = if orig.get_name() == this_fi.ident.name {
+ fluent::lint_builtin_clashing_extern_same_name
+ } else {
+ fluent::lint_builtin_clashing_extern_diff_name
+ };
tcx.struct_span_lint_hir(
CLASHING_EXTERN_DECLARATIONS,
this_fi.hir_id(),
get_relevant_span(this_fi),
+ msg,
|lint| {
let mut expected_str = DiagnosticStyledString::new();
expected_str.push(existing_decl_ty.fn_sig(tcx).to_string(), false);
let mut found_str = DiagnosticStyledString::new();
found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true);
- lint.build(if orig.get_name() == this_fi.ident.name {
- fluent::lint::builtin_clashing_extern_same_name
- } else {
- fluent::lint::builtin_clashing_extern_diff_name
- })
- .set_arg("this_fi", this_fi.ident.name)
- .set_arg("orig", orig.get_name())
- .span_label(
- get_relevant_span(orig_fi),
- fluent::lint::previous_decl_label,
- )
- .span_label(get_relevant_span(this_fi), fluent::lint::mismatch_label)
- // FIXME(davidtwco): translatable expected/found
- .note_expected_found(&"", expected_str, &"", found_str)
- .emit();
+ lint.set_arg("this_fi", this_fi.ident.name)
+ .set_arg("orig", orig.get_name())
+ .span_label(get_relevant_span(orig_fi), fluent::previous_decl_label)
+ .span_label(get_relevant_span(this_fi), fluent::mismatch_label)
+ // FIXME(davidtwco): translatable expected/found
+ .note_expected_found(&"", expected_str, &"", found_str)
},
);
}
@@ -3036,11 +3112,12 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
if is_null_ptr(cx, expr_deref) {
- cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| {
- let mut err = lint.build(fluent::lint::builtin_deref_nullptr);
- err.span_label(expr.span, fluent::lint::label);
- err.emit();
- });
+ cx.struct_span_lint(
+ DEREF_NULLPTR,
+ expr.span,
+ fluent::lint_builtin_deref_nullptr,
+ |lint| lint.span_label(expr.span, fluent::label),
+ );
}
}
}
@@ -3053,6 +3130,7 @@ declare_lint! {
/// ### Example
///
/// ```rust,compile_fail
+ /// # #![feature(asm_experimental_arch)]
/// use std::arch::asm;
///
/// fn main() {
@@ -3150,9 +3228,8 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
cx.lookup_with_diagnostics(
NAMED_ASM_LABELS,
Some(target_spans),
- |diag| {
- diag.build(fluent::lint::builtin_asm_labels).emit();
- },
+ fluent::lint_builtin_asm_labels,
+ |lint| lint,
BuiltinLintDiagnostics::NamedAsmLabel(
"only local labels of the form `<number>:` should be used in inline asm"
.to_string(),
@@ -3188,7 +3265,7 @@ declare_lint! {
/// explicitly.
///
/// To access a library from a binary target within the same crate,
- /// use `your_crate_name::` as the path path instead of `lib::`:
+ /// use `your_crate_name::` as the path instead of `lib::`:
///
/// ```rust,compile_fail
/// // bar/src/lib.rs
@@ -3224,16 +3301,14 @@ impl EarlyLintPass for SpecialModuleName {
}
match item.ident.name.as_str() {
- "lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| {
- lint.build("found module declaration for lib.rs")
+ "lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, "found module declaration for lib.rs", |lint| {
+ lint
.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")
- .emit()
}),
- "main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| {
- lint.build("found module declaration for main.rs")
+ "main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, "found module declaration for main.rs", |lint| {
+ lint
.note("a binary crate cannot be used as library")
- .emit()
}),
_ => continue
}
@@ -3253,24 +3328,27 @@ impl EarlyLintPass for UnexpectedCfgs {
for &(name, value) in cfg {
if let Some(names_valid) = &check_cfg.names_valid {
if !names_valid.contains(&name) {
- cx.lookup(UNEXPECTED_CFGS, None::<MultiSpan>, |diag| {
- diag.build(fluent::lint::builtin_unexpected_cli_config_name)
- .help(fluent::lint::help)
- .set_arg("name", name)
- .emit();
- });
+ cx.lookup(
+ UNEXPECTED_CFGS,
+ None::<MultiSpan>,
+ fluent::lint_builtin_unexpected_cli_config_name,
+ |diag| diag.help(fluent::help).set_arg("name", name),
+ );
}
}
if let Some(value) = value {
if let Some(values) = &check_cfg.values_valid.get(&name) {
if !values.contains(&value) {
- cx.lookup(UNEXPECTED_CFGS, None::<MultiSpan>, |diag| {
- diag.build(fluent::lint::builtin_unexpected_cli_config_value)
- .help(fluent::lint::help)
- .set_arg("name", name)
- .set_arg("value", value)
- .emit();
- });
+ cx.lookup(
+ UNEXPECTED_CFGS,
+ None::<MultiSpan>,
+ fluent::lint_builtin_unexpected_cli_config_value,
+ |diag| {
+ diag.help(fluent::help)
+ .set_arg("name", name)
+ .set_arg("value", value)
+ },
+ );
}
}
}
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 7ca6ec5d9..cec0003ff 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -25,15 +25,13 @@ use crate::passes::{EarlyLintPassObject, LateLintPassObject};
use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync;
-use rustc_errors::add_elided_lifetime_in_path_suggestion;
-use rustc_errors::{
- Applicability, DecorateLint, LintDiagnosticBuilder, MultiSpan, SuggestionStyle,
-};
+use rustc_errors::{add_elided_lifetime_in_path_suggestion, DiagnosticBuilder, DiagnosticMessage};
+use rustc_errors::{Applicability, DecorateLint, MultiSpan, SuggestionStyle};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
-use rustc_middle::middle::privacy::AccessLevels;
+use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::middle::stability;
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -544,7 +542,7 @@ pub struct LateContext<'tcx> {
pub param_env: ty::ParamEnv<'tcx>,
/// Items accessible from the crate being checked.
- pub access_levels: &'tcx AccessLevels,
+ pub effective_visibilities: &'tcx EffectiveVisibilities,
/// The store of registered lints and the lint levels.
pub lint_store: &'tcx LintStore,
@@ -560,7 +558,7 @@ pub struct LateContext<'tcx> {
/// Context for lint checking of the AST, after expansion, before lowering to HIR.
pub struct EarlyContext<'a> {
- pub builder: LintLevelsBuilder<'a>,
+ pub builder: LintLevelsBuilder<'a, crate::levels::TopDown>,
pub buffered: LintBuffer,
}
@@ -576,17 +574,23 @@ pub trait LintContext: Sized {
fn sess(&self) -> &Session;
fn lints(&self) -> &LintStore;
+ /// Emit a lint at the appropriate level, with an optional associated span and an existing diagnostic.
+ ///
+ /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+ ///
+ /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
fn lookup_with_diagnostics(
&self,
lint: &'static Lint,
span: Option<impl Into<MultiSpan>>,
- decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+ msg: impl Into<DiagnosticMessage>,
+ decorate: impl for<'a, 'b> FnOnce(
+ &'b mut DiagnosticBuilder<'a, ()>,
+ ) -> &'b mut DiagnosticBuilder<'a, ()>,
diagnostic: BuiltinLintDiagnostics,
) {
- self.lookup(lint, span, |lint| {
- // We first generate a blank diagnostic.
- let mut db = lint.build("");
-
+ // We first generate a blank diagnostic.
+ self.lookup(lint, span, msg,|db| {
// Now, set up surrounding context.
let sess = self.sess();
match diagnostic {
@@ -660,7 +664,7 @@ pub trait LintContext: Sized {
) => {
add_elided_lifetime_in_path_suggestion(
sess.source_map(),
- &mut db,
+ db,
n,
path_span,
incl_angl_brckt,
@@ -696,7 +700,7 @@ pub trait LintContext: Sized {
}
}
BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) => {
- stability::deprecation_suggestion(&mut db, "macro", suggestion, span)
+ stability::deprecation_suggestion(db, "macro", suggestion, span)
}
BuiltinLintDiagnostics::UnusedDocComment(span) => {
db.span_label(span, "rustdoc does not generate documentation for macro invocations");
@@ -867,17 +871,25 @@ pub trait LintContext: Sized {
}
}
// Rewrap `db`, and pass control to the user.
- decorate(LintDiagnosticBuilder::new(db));
+ decorate(db)
});
}
// FIXME: These methods should not take an Into<MultiSpan> -- instead, callers should need to
// set the span in their `decorate` function (preferably using set_span).
+ /// Emit a lint at the appropriate level, with an optional associated span.
+ ///
+ /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+ ///
+ /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
fn lookup<S: Into<MultiSpan>>(
&self,
lint: &'static Lint,
span: Option<S>,
- decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+ msg: impl Into<DiagnosticMessage>,
+ decorate: impl for<'a, 'b> FnOnce(
+ &'b mut DiagnosticBuilder<'a, ()>,
+ ) -> &'b mut DiagnosticBuilder<'a, ()>,
);
/// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`,
@@ -888,31 +900,48 @@ pub trait LintContext: Sized {
span: S,
decorator: impl for<'a> DecorateLint<'a, ()>,
) {
- self.lookup(lint, Some(span), |diag| decorator.decorate_lint(diag));
+ self.lookup(lint, Some(span), decorator.msg(), |diag| decorator.decorate_lint(diag));
}
+ /// Emit a lint at the appropriate level, with an associated span.
+ ///
+ /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+ ///
+ /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
fn struct_span_lint<S: Into<MultiSpan>>(
&self,
lint: &'static Lint,
span: S,
- decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+ msg: impl Into<DiagnosticMessage>,
+ decorate: impl for<'a, 'b> FnOnce(
+ &'b mut DiagnosticBuilder<'a, ()>,
+ ) -> &'b mut DiagnosticBuilder<'a, ()>,
) {
- self.lookup(lint, Some(span), decorate);
+ self.lookup(lint, Some(span), msg, decorate);
}
/// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically
/// generated by `#[derive(LintDiagnostic)]`).
fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> DecorateLint<'a, ()>) {
- self.lookup(lint, None as Option<Span>, |diag| decorator.decorate_lint(diag));
+ self.lookup(lint, None as Option<Span>, decorator.msg(), |diag| {
+ decorator.decorate_lint(diag)
+ });
}
/// Emit a lint at the appropriate level, with no associated span.
+ ///
+ /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+ ///
+ /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
fn lint(
&self,
lint: &'static Lint,
- decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+ msg: impl Into<DiagnosticMessage>,
+ decorate: impl for<'a, 'b> FnOnce(
+ &'b mut DiagnosticBuilder<'a, ()>,
+ ) -> &'b mut DiagnosticBuilder<'a, ()>,
) {
- self.lookup(lint, None as Option<Span>, decorate);
+ self.lookup(lint, None as Option<Span>, msg, decorate);
}
/// This returns the lint level for the given lint at the current location.
@@ -975,13 +1004,16 @@ impl<'tcx> LintContext for LateContext<'tcx> {
&self,
lint: &'static Lint,
span: Option<S>,
- decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+ msg: impl Into<DiagnosticMessage>,
+ decorate: impl for<'a, 'b> FnOnce(
+ &'b mut DiagnosticBuilder<'a, ()>,
+ ) -> &'b mut DiagnosticBuilder<'a, ()>,
) {
let hir_id = self.last_node_with_lint_attrs;
match span {
- Some(s) => self.tcx.struct_span_lint_hir(lint, hir_id, s, decorate),
- None => self.tcx.struct_lint_node(lint, hir_id, decorate),
+ Some(s) => self.tcx.struct_span_lint_hir(lint, hir_id, s, msg, decorate),
+ None => self.tcx.struct_lint_node(lint, hir_id, msg, decorate),
}
}
@@ -1006,9 +1038,12 @@ impl LintContext for EarlyContext<'_> {
&self,
lint: &'static Lint,
span: Option<S>,
- decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+ msg: impl Into<DiagnosticMessage>,
+ decorate: impl for<'a, 'b> FnOnce(
+ &'b mut DiagnosticBuilder<'a, ()>,
+ ) -> &'b mut DiagnosticBuilder<'a, ()>,
) {
- self.builder.struct_lint(lint, span.map(|s| s.into()), decorate)
+ self.builder.struct_lint(lint, span.map(|s| s.into()), msg, decorate)
}
fn get_lint_level(&self, lint: &'static Lint) -> Level {
@@ -1048,7 +1083,7 @@ impl<'tcx> LateContext<'tcx> {
.filter(|typeck_results| typeck_results.hir_owner == id.owner)
.or_else(|| {
if self.tcx.has_typeck_results(id.owner.to_def_id()) {
- Some(self.tcx.typeck(id.owner))
+ Some(self.tcx.typeck(id.owner.def_id))
} else {
None
}
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 96ecd79a6..aee870dd2 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -43,9 +43,8 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
self.context.lookup_with_diagnostics(
lint_id.lint,
Some(span),
- |lint| {
- lint.build(msg).emit();
- },
+ msg,
+ |lint| lint,
diagnostic,
);
}
@@ -59,6 +58,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
F: FnOnce(&mut Self),
{
let is_crate_node = id == ast::CRATE_NODE_ID;
+ debug!(?id);
let push = self.context.builder.push(attrs, is_crate_node, None);
self.check_id(id);
@@ -409,7 +409,7 @@ pub fn check_ast_node<'a>(
if sess.opts.unstable_opts.no_interleave_lints {
for (i, pass) in passes.iter_mut().enumerate() {
buffered =
- sess.prof.extra_verbose_generic_activity("run_lint", pass.name()).run(|| {
+ sess.prof.verbose_generic_activity_with_arg("run_lint", pass.name()).run(|| {
early_lint_node(
sess,
!pre_expansion && i == 0,
diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
index f41ee6404..f9d746622 100644
--- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
+++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
@@ -50,26 +50,24 @@ fn enforce_mem_discriminant(
) {
let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0);
if is_non_enum(ty_param) {
- cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, expr_span, |builder| {
- builder
- .build(fluent::lint::enum_intrinsics_mem_discriminant)
- .set_arg("ty_param", ty_param)
- .span_note(args_span, fluent::lint::note)
- .emit();
- });
+ cx.struct_span_lint(
+ ENUM_INTRINSICS_NON_ENUMS,
+ expr_span,
+ fluent::lint_enum_intrinsics_mem_discriminant,
+ |lint| lint.set_arg("ty_param", ty_param).span_note(args_span, fluent::note),
+ );
}
}
fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, span: Span) {
let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0);
if is_non_enum(ty_param) {
- cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, span, |builder| {
- builder
- .build(fluent::lint::enum_intrinsics_mem_variant)
- .set_arg("ty_param", ty_param)
- .note(fluent::lint::note)
- .emit();
- });
+ cx.struct_span_lint(
+ ENUM_INTRINSICS_NON_ENUMS,
+ span,
+ fluent::lint_enum_intrinsics_mem_variant,
+ |lint| lint.set_arg("ty_param", ty_param).note(fluent::note),
+ );
}
}
diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs
index 5c183d409..a49d1bdac 100644
--- a/compiler/rustc_lint/src/errors.rs
+++ b/compiler/rustc_lint/src/errors.rs
@@ -1,10 +1,13 @@
-use rustc_errors::{fluent, AddSubdiagnostic, ErrorGuaranteed, Handler};
-use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
-use rustc_session::{lint::Level, SessionDiagnostic};
+use rustc_errors::{
+ fluent, AddToDiagnostic, Diagnostic, ErrorGuaranteed, Handler, IntoDiagnostic,
+ SubdiagnosticMessage,
+};
+use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_session::lint::Level;
use rustc_span::{Span, Symbol};
-#[derive(SessionDiagnostic)]
-#[diag(lint::overruled_attribute, code = "E0453")]
+#[derive(Diagnostic)]
+#[diag(lint_overruled_attribute, code = "E0453")]
pub struct OverruledAttribute {
#[primary_span]
pub span: Span,
@@ -22,28 +25,31 @@ pub enum OverruledAttributeSub {
CommandLineSource,
}
-impl AddSubdiagnostic for OverruledAttributeSub {
- fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+impl AddToDiagnostic for OverruledAttributeSub {
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+ where
+ F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+ {
match self {
OverruledAttributeSub::DefaultSource { id } => {
- diag.note(fluent::lint::default_source);
+ diag.note(fluent::lint_default_source);
diag.set_arg("id", id);
}
OverruledAttributeSub::NodeSource { span, reason } => {
- diag.span_label(span, fluent::lint::node_source);
+ diag.span_label(span, fluent::lint_node_source);
if let Some(rationale) = reason {
diag.note(rationale.as_str());
}
}
OverruledAttributeSub::CommandLineSource => {
- diag.note(fluent::lint::command_line_source);
+ diag.note(fluent::lint_command_line_source);
}
}
}
}
-#[derive(SessionDiagnostic)]
-#[diag(lint::malformed_attribute, code = "E0452")]
+#[derive(Diagnostic)]
+#[diag(lint_malformed_attribute, code = "E0452")]
pub struct MalformedAttribute {
#[primary_span]
pub span: Span,
@@ -51,18 +57,18 @@ pub struct MalformedAttribute {
pub sub: MalformedAttributeSub,
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub enum MalformedAttributeSub {
- #[label(lint::bad_attribute_argument)]
+ #[label(lint_bad_attribute_argument)]
BadAttributeArgument(#[primary_span] Span),
- #[label(lint::reason_must_be_string_literal)]
+ #[label(lint_reason_must_be_string_literal)]
ReasonMustBeStringLiteral(#[primary_span] Span),
- #[label(lint::reason_must_come_last)]
+ #[label(lint_reason_must_come_last)]
ReasonMustComeLast(#[primary_span] Span),
}
-#[derive(SessionDiagnostic)]
-#[diag(lint::unknown_tool_in_scoped_lint, code = "E0710")]
+#[derive(Diagnostic)]
+#[diag(lint_unknown_tool_in_scoped_lint, code = "E0710")]
pub struct UnknownToolInScopedLint {
#[primary_span]
pub span: Option<Span>,
@@ -72,8 +78,8 @@ pub struct UnknownToolInScopedLint {
pub is_nightly_build: Option<()>,
}
-#[derive(SessionDiagnostic)]
-#[diag(lint::builtin_ellipsis_inclusive_range_patterns, code = "E0783")]
+#[derive(Diagnostic)]
+#[diag(lint_builtin_ellipsis_inclusive_range_patterns, code = "E0783")]
pub struct BuiltinEllpisisInclusiveRangePatterns {
#[primary_span]
pub span: Span,
@@ -82,33 +88,15 @@ pub struct BuiltinEllpisisInclusiveRangePatterns {
pub replace: String,
}
+#[derive(Subdiagnostic)]
+#[note(lint_requested_level)]
pub struct RequestedLevel {
pub level: Level,
pub lint_name: String,
}
-impl AddSubdiagnostic for RequestedLevel {
- fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
- diag.note(fluent::lint::requested_level);
- diag.set_arg(
- "level",
- match self.level {
- Level::Allow => "-A",
- Level::Warn => "-W",
- Level::ForceWarn(_) => "--force-warn",
- Level::Deny => "-D",
- Level::Forbid => "-F",
- Level::Expect(_) => {
- unreachable!("lints with the level of `expect` should not run this code");
- }
- },
- );
- diag.set_arg("lint_name", self.lint_name);
- }
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(lint::unsupported_group, code = "E0602")]
+#[derive(Diagnostic)]
+#[diag(lint_unsupported_group, code = "E0602")]
pub struct UnsupportedGroup {
pub lint_group: String,
}
@@ -119,15 +107,15 @@ pub struct CheckNameUnknown {
pub sub: RequestedLevel,
}
-impl SessionDiagnostic<'_> for CheckNameUnknown {
+impl IntoDiagnostic<'_> for CheckNameUnknown {
fn into_diagnostic(
self,
handler: &Handler,
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
- let mut diag = handler.struct_err(fluent::lint::check_name_unknown);
+ let mut diag = handler.struct_err(fluent::lint_check_name_unknown);
diag.code(rustc_errors::error_code!(E0602));
if let Some(suggestion) = self.suggestion {
- diag.help(fluent::lint::help);
+ diag.help(fluent::help);
diag.set_arg("suggestion", suggestion);
}
diag.set_arg("lint_name", self.lint_name);
@@ -136,24 +124,24 @@ impl SessionDiagnostic<'_> for CheckNameUnknown {
}
}
-#[derive(SessionDiagnostic)]
-#[diag(lint::check_name_unknown_tool, code = "E0602")]
+#[derive(Diagnostic)]
+#[diag(lint_check_name_unknown_tool, code = "E0602")]
pub struct CheckNameUnknownTool {
pub tool_name: Symbol,
#[subdiagnostic]
pub sub: RequestedLevel,
}
-#[derive(SessionDiagnostic)]
-#[diag(lint::check_name_warning)]
+#[derive(Diagnostic)]
+#[diag(lint_check_name_warning)]
pub struct CheckNameWarning {
pub msg: String,
#[subdiagnostic]
pub sub: RequestedLevel,
}
-#[derive(SessionDiagnostic)]
-#[diag(lint::check_name_deprecated)]
+#[derive(Diagnostic)]
+#[diag(lint_check_name_deprecated)]
pub struct CheckNameDeprecated {
pub lint_name: String,
pub new_name: String,
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index 699e81543..cf8f31bcb 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -16,8 +16,10 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
return;
}
+ let lint_expectations = tcx.lint_expectations(());
let fulfilled_expectations = tcx.sess.diagnostic().steal_fulfilled_expectation_ids();
- let lint_expectations = &tcx.lint_levels(()).lint_expectations;
+
+ tracing::debug!(?lint_expectations, ?fulfilled_expectations);
for (id, expectation) in lint_expectations {
// This check will always be true, since `lint_expectations` only
@@ -43,17 +45,17 @@ fn emit_unfulfilled_expectation_lint(
builtin::UNFULFILLED_LINT_EXPECTATIONS,
hir_id,
expectation.emission_span,
- |diag| {
- let mut diag = diag.build(fluent::lint::expectation);
+ fluent::lint_expectation,
+ |lint| {
if let Some(rationale) = expectation.reason {
- diag.note(rationale.as_str());
+ lint.note(rationale.as_str());
}
if expectation.is_unfulfilled_lint_expectations {
- diag.note(fluent::lint::note);
+ lint.note(fluent::note);
}
- diag.emit();
+ lint
},
);
}
diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
new file mode 100644
index 000000000..ed8d424e0
--- /dev/null
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -0,0 +1,183 @@
+use crate::{LateContext, LateLintPass, LintContext};
+
+use hir::{Expr, Pat};
+use rustc_errors::{Applicability, DelayDm};
+use rustc_hir as hir;
+use rustc_infer::traits::TraitEngine;
+use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause};
+use rustc_middle::ty::{self, List};
+use rustc_span::{sym, Span};
+use rustc_trait_selection::traits::TraitEngineExt;
+
+declare_lint! {
+ /// The `for_loops_over_fallibles` lint checks for `for` loops over `Option` or `Result` values.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let opt = Some(1);
+ /// for x in opt { /* ... */}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Both `Option` and `Result` implement `IntoIterator` trait, which allows using them in a `for` loop.
+ /// `for` loop over `Option` or `Result` will iterate either 0 (if the value is `None`/`Err(_)`)
+ /// or 1 time (if the value is `Some(_)`/`Ok(_)`). This is not very useful and is more clearly expressed
+ /// via `if let`.
+ ///
+ /// `for` loop can also be accidentally written with the intention to call a function multiple times,
+ /// while the function returns `Some(_)`, in these cases `while let` loop should be used instead.
+ ///
+ /// The "intended" use of `IntoIterator` implementations for `Option` and `Result` is passing them to
+ /// generic code that expects something implementing `IntoIterator`. For example using `.chain(option)`
+ /// to optionally add a value to an iterator.
+ pub FOR_LOOPS_OVER_FALLIBLES,
+ Warn,
+ "for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`"
+}
+
+declare_lint_pass!(ForLoopsOverFallibles => [FOR_LOOPS_OVER_FALLIBLES]);
+
+impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ let Some((pat, arg)) = extract_for_loop(expr) else { return };
+
+ let ty = cx.typeck_results().expr_ty(arg);
+
+ let &ty::Adt(adt, substs) = ty.kind() else { return };
+
+ let (article, ty, var) = match adt.did() {
+ did if cx.tcx.is_diagnostic_item(sym::Option, did) => ("an", "Option", "Some"),
+ did if cx.tcx.is_diagnostic_item(sym::Result, did) => ("a", "Result", "Ok"),
+ _ => return,
+ };
+
+ let msg = DelayDm(|| {
+ format!(
+ "for loop over {article} `{ty}`. This is more readably written as an `if let` statement",
+ )
+ });
+
+ cx.struct_span_lint(FOR_LOOPS_OVER_FALLIBLES, arg.span, msg, |lint| {
+ if let Some(recv) = extract_iterator_next_call(cx, arg)
+ && let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span)
+ {
+ lint.span_suggestion(
+ recv.span.between(arg.span.shrink_to_hi()),
+ format!("to iterate over `{recv_snip}` remove the call to `next`"),
+ ".by_ref()",
+ Applicability::MaybeIncorrect
+ );
+ } else {
+ lint.multipart_suggestion_verbose(
+ format!("to check pattern in a loop use `while let`"),
+ vec![
+ // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
+ (expr.span.with_hi(pat.span.lo()), format!("while let {var}(")),
+ (pat.span.between(arg.span), format!(") = ")),
+ ],
+ Applicability::MaybeIncorrect
+ );
+ }
+
+ if suggest_question_mark(cx, adt, substs, expr.span) {
+ lint.span_suggestion(
+ arg.span.shrink_to_hi(),
+ "consider unwrapping the `Result` with `?` to iterate over its contents",
+ "?",
+ Applicability::MaybeIncorrect,
+ );
+ }
+
+ lint.multipart_suggestion_verbose(
+ "consider using `if let` to clear intent",
+ vec![
+ // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
+ (expr.span.with_hi(pat.span.lo()), format!("if let {var}(")),
+ (pat.span.between(arg.span), format!(") = ")),
+ ],
+ Applicability::MaybeIncorrect,
+ )
+ })
+ }
+}
+
+fn extract_for_loop<'tcx>(expr: &Expr<'tcx>) -> Option<(&'tcx Pat<'tcx>, &'tcx Expr<'tcx>)> {
+ if let hir::ExprKind::DropTemps(e) = expr.kind
+ && let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind
+ && let hir::ExprKind::Call(_, [arg]) = iterexpr.kind
+ && let hir::ExprKind::Loop(block, ..) = arm.body.kind
+ && let [stmt] = block.stmts
+ && let hir::StmtKind::Expr(e) = stmt.kind
+ && let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind
+ && let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind
+ {
+ Some((field.pat, arg))
+ } else {
+ None
+ }
+}
+
+fn extract_iterator_next_call<'tcx>(
+ cx: &LateContext<'_>,
+ expr: &Expr<'tcx>,
+) -> Option<&'tcx Expr<'tcx>> {
+ // This won't work for `Iterator::next(iter)`, is this an issue?
+ if let hir::ExprKind::MethodCall(_, recv, _, _) = expr.kind
+ && cx.typeck_results().type_dependent_def_id(expr.hir_id) == cx.tcx.lang_items().next_fn()
+ {
+ Some(recv)
+ } else {
+ return None
+ }
+}
+
+fn suggest_question_mark<'tcx>(
+ cx: &LateContext<'tcx>,
+ adt: ty::AdtDef<'tcx>,
+ substs: &List<ty::GenericArg<'tcx>>,
+ span: Span,
+) -> bool {
+ let Some(body_id) = cx.enclosing_body else { return false };
+ let Some(into_iterator_did) = cx.tcx.get_diagnostic_item(sym::IntoIterator) else { return false };
+
+ if !cx.tcx.is_diagnostic_item(sym::Result, adt.did()) {
+ return false;
+ }
+
+ // Check that the function/closure/constant we are in has a `Result` type.
+ // Otherwise suggesting using `?` may not be a good idea.
+ {
+ let ty = cx.typeck_results().expr_ty(&cx.tcx.hir().body(body_id).value);
+ let ty::Adt(ret_adt, ..) = ty.kind() else { return false };
+ if !cx.tcx.is_diagnostic_item(sym::Result, ret_adt.did()) {
+ return false;
+ }
+ }
+
+ let ty = substs.type_at(0);
+ let infcx = cx.tcx.infer_ctxt().build();
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+
+ let cause = ObligationCause::new(
+ span,
+ body_id.hir_id,
+ rustc_infer::traits::ObligationCauseCode::MiscObligation,
+ );
+ fulfill_cx.register_bound(
+ &infcx,
+ ty::ParamEnv::empty(),
+ // Erase any region vids from the type, which may not be resolved
+ infcx.tcx.erase_regions(ty),
+ into_iterator_did,
+ cause,
+ );
+
+ // Select all, including ambiguous predicates
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+
+ errors.is_empty()
+}
diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
index 8f2222132..7e884e990 100644
--- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
+++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
@@ -60,52 +60,56 @@ impl HiddenUnicodeCodepoints {
})
.collect();
- cx.struct_span_lint(TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, |lint| {
- let mut err = lint.build(fluent::lint::hidden_unicode_codepoints);
- err.set_arg("label", label);
- err.set_arg("count", spans.len());
- err.span_label(span, fluent::lint::label);
- err.note(fluent::lint::note);
- if point_at_inner_spans {
- for (c, span) in &spans {
- err.span_label(*span, format!("{:?}", c));
+ cx.struct_span_lint(
+ TEXT_DIRECTION_CODEPOINT_IN_LITERAL,
+ span,
+ fluent::lint_hidden_unicode_codepoints,
+ |lint| {
+ lint.set_arg("label", label);
+ lint.set_arg("count", spans.len());
+ lint.span_label(span, fluent::label);
+ lint.note(fluent::note);
+ if point_at_inner_spans {
+ for (c, span) in &spans {
+ lint.span_label(*span, format!("{:?}", c));
+ }
}
- }
- if point_at_inner_spans && !spans.is_empty() {
- err.multipart_suggestion_with_style(
- fluent::lint::suggestion_remove,
- spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
- Applicability::MachineApplicable,
- SuggestionStyle::HideCodeAlways,
- );
- err.multipart_suggestion(
- fluent::lint::suggestion_escape,
- spans
- .into_iter()
- .map(|(c, span)| {
- let c = format!("{:?}", c);
- (span, c[1..c.len() - 1].to_string())
- })
- .collect(),
- Applicability::MachineApplicable,
- );
- } else {
- // FIXME: in other suggestions we've reversed the inner spans of doc comments. We
- // should do the same here to provide the same good suggestions as we do for
- // literals above.
- err.set_arg(
- "escaped",
- spans
- .into_iter()
- .map(|(c, _)| format!("{:?}", c))
- .collect::<Vec<String>>()
- .join(", "),
- );
- err.note(fluent::lint::suggestion_remove);
- err.note(fluent::lint::no_suggestion_note_escape);
- }
- err.emit();
- });
+ if point_at_inner_spans && !spans.is_empty() {
+ lint.multipart_suggestion_with_style(
+ fluent::suggestion_remove,
+ spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
+ Applicability::MachineApplicable,
+ SuggestionStyle::HideCodeAlways,
+ );
+ lint.multipart_suggestion(
+ fluent::suggestion_escape,
+ spans
+ .into_iter()
+ .map(|(c, span)| {
+ let c = format!("{:?}", c);
+ (span, c[1..c.len() - 1].to_string())
+ })
+ .collect(),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ // FIXME: in other suggestions we've reversed the inner spans of doc comments. We
+ // should do the same here to provide the same good suggestions as we do for
+ // literals above.
+ lint.set_arg(
+ "escaped",
+ spans
+ .into_iter()
+ .map(|(c, _)| format!("{:?}", c))
+ .collect::<Vec<String>>()
+ .join(", "),
+ );
+ lint.note(fluent::suggestion_remove);
+ lint.note(fluent::no_suggestion_note_escape);
+ }
+ lint
+ },
+ );
}
}
impl EarlyLintPass for HiddenUnicodeCodepoints {
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index dd1fc5916..11e4650cb 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -34,13 +34,16 @@ impl LateLintPass<'_> for DefaultHashTypes {
Some(sym::HashSet) => "FxHashSet",
_ => return,
};
- cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| {
- lint.build(fluent::lint::default_hash_types)
- .set_arg("preferred", replace)
- .set_arg("used", cx.tcx.item_name(def_id))
- .note(fluent::lint::note)
- .emit();
- });
+ cx.struct_span_lint(
+ DEFAULT_HASH_TYPES,
+ path.span,
+ fluent::lint_default_hash_types,
+ |lint| {
+ lint.set_arg("preferred", replace)
+ .set_arg("used", cx.tcx.item_name(def_id))
+ .note(fluent::note)
+ },
+ );
}
}
@@ -80,12 +83,12 @@ impl LateLintPass<'_> for QueryStability {
if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) {
let def_id = instance.def_id();
if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
- cx.struct_span_lint(POTENTIAL_QUERY_INSTABILITY, span, |lint| {
- lint.build(fluent::lint::query_instability)
- .set_arg("query", cx.tcx.item_name(def_id))
- .note(fluent::lint::note)
- .emit();
- })
+ cx.struct_span_lint(
+ POTENTIAL_QUERY_INSTABILITY,
+ span,
+ fluent::lint_query_instability,
+ |lint| lint.set_arg("query", cx.tcx.item_name(def_id)).note(fluent::note),
+ )
}
}
}
@@ -123,15 +126,14 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
let span = path.span.with_hi(
segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()
);
- cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
- lint.build(fluent::lint::tykind_kind)
+ cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, fluent::lint_tykind_kind, |lint| {
+ lint
.span_suggestion(
span,
- fluent::lint::suggestion,
+ fluent::suggestion,
"ty",
Applicability::MaybeIncorrect, // ty maybe needs an import
)
- .emit();
});
}
}
@@ -140,85 +142,85 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
match &ty.kind {
TyKind::Path(QPath::Resolved(_, path)) => {
if lint_ty_kind_usage(cx, &path.res) {
- cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
- let hir = cx.tcx.hir();
- match hir.find(hir.get_parent_node(ty.hir_id)) {
- Some(Node::Pat(Pat {
- kind:
- PatKind::Path(qpath)
- | PatKind::TupleStruct(qpath, ..)
- | PatKind::Struct(qpath, ..),
- ..
- })) => {
- if let QPath::TypeRelative(qpath_ty, ..) = qpath
- && qpath_ty.hir_id == ty.hir_id
- {
- lint.build(fluent::lint::tykind_kind)
- .span_suggestion(
- path.span,
- fluent::lint::suggestion,
- "ty",
- Applicability::MaybeIncorrect, // ty maybe needs an import
- )
- .emit();
- return;
- }
+ let hir = cx.tcx.hir();
+ let span = match hir.find(hir.get_parent_node(ty.hir_id)) {
+ Some(Node::Pat(Pat {
+ kind:
+ PatKind::Path(qpath)
+ | PatKind::TupleStruct(qpath, ..)
+ | PatKind::Struct(qpath, ..),
+ ..
+ })) => {
+ if let QPath::TypeRelative(qpath_ty, ..) = qpath
+ && qpath_ty.hir_id == ty.hir_id
+ {
+ Some(path.span)
+ } else {
+ None
}
- Some(Node::Expr(Expr {
- kind: ExprKind::Path(qpath),
- ..
- })) => {
- if let QPath::TypeRelative(qpath_ty, ..) = qpath
- && qpath_ty.hir_id == ty.hir_id
- {
- lint.build(fluent::lint::tykind_kind)
- .span_suggestion(
- path.span,
- fluent::lint::suggestion,
- "ty",
- Applicability::MaybeIncorrect, // ty maybe needs an import
- )
- .emit();
- return;
- }
+ }
+ Some(Node::Expr(Expr {
+ kind: ExprKind::Path(qpath),
+ ..
+ })) => {
+ if let QPath::TypeRelative(qpath_ty, ..) = qpath
+ && qpath_ty.hir_id == ty.hir_id
+ {
+ Some(path.span)
+ } else {
+ None
}
- // Can't unify these two branches because qpath below is `&&` and above is `&`
- // and `A | B` paths don't play well together with adjustments, apparently.
- Some(Node::Expr(Expr {
- kind: ExprKind::Struct(qpath, ..),
- ..
- })) => {
- if let QPath::TypeRelative(qpath_ty, ..) = qpath
- && qpath_ty.hir_id == ty.hir_id
- {
- lint.build(fluent::lint::tykind_kind)
- .span_suggestion(
- path.span,
- fluent::lint::suggestion,
- "ty",
- Applicability::MaybeIncorrect, // ty maybe needs an import
- )
- .emit();
- return;
- }
+ }
+ // Can't unify these two branches because qpath below is `&&` and above is `&`
+ // and `A | B` paths don't play well together with adjustments, apparently.
+ Some(Node::Expr(Expr {
+ kind: ExprKind::Struct(qpath, ..),
+ ..
+ })) => {
+ if let QPath::TypeRelative(qpath_ty, ..) = qpath
+ && qpath_ty.hir_id == ty.hir_id
+ {
+ Some(path.span)
+ } else {
+ None
}
- _ => {}
}
- lint.build(fluent::lint::tykind).help(fluent::lint::help).emit();
- })
+ _ => None
+ };
+
+ match span {
+ Some(span) => {
+ cx.struct_span_lint(
+ USAGE_OF_TY_TYKIND,
+ path.span,
+ fluent::lint_tykind_kind,
+ |lint| lint.span_suggestion(
+ span,
+ fluent::suggestion,
+ "ty",
+ Applicability::MaybeIncorrect, // ty maybe needs an import
+ )
+ )
+ },
+ None => cx.struct_span_lint(
+ USAGE_OF_TY_TYKIND,
+ path.span,
+ fluent::lint_tykind,
+ |lint| lint.help(fluent::help)
+ )
+ }
} else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
if path.segments.len() > 1 {
- cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
- lint.build(fluent::lint::ty_qualified)
+ cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, fluent::lint_ty_qualified, |lint| {
+ lint
.set_arg("ty", t.clone())
.span_suggestion(
path.span,
- fluent::lint::suggestion,
+ fluent::suggestion,
t,
// The import probably needs to be changed
Applicability::MaybeIncorrect,
)
- .emit();
})
}
}
@@ -244,7 +246,7 @@ fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, path: &Path<'_>) -> Option<String> {
}
}
// Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
- Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => {
+ Res::SelfTyAlias { alias_to: did, is_trait_impl: false, .. } => {
if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(adt.did())
{
@@ -308,11 +310,8 @@ impl EarlyLintPass for LintPassImpl {
cx.struct_span_lint(
LINT_PASS_IMPL_WITHOUT_MACRO,
lint_pass.path.span,
- |lint| {
- lint.build(fluent::lint::lintpass_by_hand)
- .help(fluent::lint::help)
- .emit();
- },
+ fluent::lint_lintpass_by_hand,
+ |lint| lint.help(fluent::help),
)
}
}
@@ -349,12 +348,12 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword {
if is_doc_keyword(v) {
return;
}
- cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| {
- lint.build(fluent::lint::non_existant_doc_keyword)
- .set_arg("keyword", v)
- .help(fluent::lint::help)
- .emit();
- });
+ cx.struct_span_lint(
+ EXISTING_DOC_KEYWORD,
+ attr.span,
+ fluent::lint_non_existant_doc_keyword,
+ |lint| lint.set_arg("keyword", v).help(fluent::help),
+ );
}
}
}
@@ -372,7 +371,7 @@ declare_tool_lint! {
declare_tool_lint! {
pub rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL,
Allow,
- "prevent creation of diagnostics outside of `SessionDiagnostic`/`AddSubdiagnostic` impls",
+ "prevent creation of diagnostics outside of `IntoDiagnostic`/`AddToDiagnostic` impls",
report_in_external_macro: true
}
@@ -404,7 +403,7 @@ impl LateLintPass<'_> for Diagnostics {
let Impl { of_trait: Some(of_trait), .. } = impl_ &&
let Some(def_id) = of_trait.trait_def_id() &&
let Some(name) = cx.tcx.get_diagnostic_name(def_id) &&
- matches!(name, sym::SessionDiagnostic | sym::AddSubdiagnostic | sym::DecorateLint)
+ matches!(name, sym::IntoDiagnostic | sym::AddToDiagnostic | sym::DecorateLint)
{
found_impl = true;
break;
@@ -412,9 +411,12 @@ impl LateLintPass<'_> for Diagnostics {
}
debug!(?found_impl);
if !found_parent_with_attr && !found_impl {
- cx.struct_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, |lint| {
- lint.build(fluent::lint::diag_out_of_impl).emit();
- })
+ cx.struct_span_lint(
+ DIAGNOSTIC_OUTSIDE_OF_IMPL,
+ span,
+ fluent::lint_diag_out_of_impl,
+ |lint| lint,
+ )
}
let mut found_diagnostic_message = false;
@@ -430,9 +432,12 @@ impl LateLintPass<'_> for Diagnostics {
}
debug!(?found_diagnostic_message);
if !found_parent_with_attr && !found_diagnostic_message {
- cx.struct_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, |lint| {
- lint.build(fluent::lint::untranslatable_diag).emit();
- })
+ cx.struct_span_lint(
+ UNTRANSLATABLE_DIAGNOSTIC,
+ span,
+ fluent::lint_untranslatable_diag,
+ |lint| lint,
+ )
}
}
}
@@ -464,8 +469,8 @@ impl LateLintPass<'_> for BadOptAccess {
let Some(literal) = item.literal() &&
let ast::LitKind::Str(val, _) = literal.kind
{
- cx.struct_span_lint(BAD_OPT_ACCESS, expr.span, |lint| {
- lint.build(val.as_str()).emit(); }
+ cx.struct_span_lint(BAD_OPT_ACCESS, expr.span, val.as_str(), |lint|
+ lint
);
}
}
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index da6f1c5ee..303fcb1a1 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -338,14 +338,14 @@ fn late_lint_mod_pass<'tcx, T: LateLintPass<'tcx>>(
module_def_id: LocalDefId,
pass: T,
) {
- let access_levels = &tcx.privacy_access_levels(());
+ let effective_visibilities = &tcx.effective_visibilities(());
let context = LateContext {
tcx,
enclosing_body: None,
cached_typeck_results: Cell::new(None),
param_env: ty::ParamEnv::empty(),
- access_levels,
+ effective_visibilities,
lint_store: unerased_lint_store(tcx),
last_node_with_lint_attrs: tcx.hir().local_def_id_to_hir_id(module_def_id),
generics: None,
@@ -386,14 +386,14 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx>>(
}
fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) {
- let access_levels = &tcx.privacy_access_levels(());
+ let effective_visibilities = &tcx.effective_visibilities(());
let context = LateContext {
tcx,
enclosing_body: None,
cached_typeck_results: Cell::new(None),
param_env: ty::ParamEnv::empty(),
- access_levels,
+ effective_visibilities,
lint_store: unerased_lint_store(tcx),
last_node_with_lint_attrs: hir::CRATE_HIR_ID,
generics: None,
@@ -425,20 +425,23 @@ fn late_lint_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints
late_lint_pass_crate(tcx, builtin_lints);
} else {
for pass in &mut passes {
- tcx.sess.prof.extra_verbose_generic_activity("run_late_lint", pass.name()).run(|| {
- late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
- });
+ tcx.sess.prof.verbose_generic_activity_with_arg("run_late_lint", pass.name()).run(
+ || {
+ late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
+ },
+ );
}
let mut passes: Vec<_> =
unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)(tcx)).collect();
for pass in &mut passes {
- tcx.sess.prof.extra_verbose_generic_activity("run_late_module_lint", pass.name()).run(
- || {
+ tcx.sess
+ .prof
+ .verbose_generic_activity_with_arg("run_late_module_lint", pass.name())
+ .run(|| {
late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
- },
- );
+ });
}
}
}
diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs
index 7e885e6c5..78f355ec3 100644
--- a/compiler/rustc_lint/src/let_underscore.rs
+++ b/compiler/rustc_lint/src/let_underscore.rs
@@ -1,5 +1,5 @@
use crate::{LateContext, LateLintPass, LintContext};
-use rustc_errors::{Applicability, LintDiagnosticBuilder, MultiSpan};
+use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan};
use rustc_hir as hir;
use rustc_middle::ty;
use rustc_span::Symbol;
@@ -128,48 +128,41 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
init.span,
"this binding will immediately drop the value assigned to it".to_string(),
);
- cx.struct_span_lint(LET_UNDERSCORE_LOCK, span, |lint| {
- build_and_emit_lint(
- lint,
- local,
- init.span,
- "non-binding let on a synchronization lock",
- )
- })
+ cx.struct_span_lint(
+ LET_UNDERSCORE_LOCK,
+ span,
+ "non-binding let on a synchronization lock",
+ |lint| build_lint(lint, local, init.span),
+ )
} else {
- cx.struct_span_lint(LET_UNDERSCORE_DROP, local.span, |lint| {
- build_and_emit_lint(
- lint,
- local,
- init.span,
- "non-binding let on a type that implements `Drop`",
- );
- })
+ cx.struct_span_lint(
+ LET_UNDERSCORE_DROP,
+ local.span,
+ "non-binding let on a type that implements `Drop`",
+ |lint| build_lint(lint, local, init.span),
+ )
}
}
}
}
-fn build_and_emit_lint(
- lint: LintDiagnosticBuilder<'_, ()>,
+fn build_lint<'a, 'b>(
+ lint: &'a mut DiagnosticBuilder<'b, ()>,
local: &hir::Local<'_>,
init_span: rustc_span::Span,
- msg: &str,
-) {
- lint.build(msg)
- .span_suggestion_verbose(
- local.pat.span,
- "consider binding to an unused variable to avoid immediately dropping the value",
- "_unused",
- Applicability::MachineApplicable,
- )
- .multipart_suggestion(
- "consider immediately dropping the value",
- vec![
- (local.span.until(init_span), "drop(".to_string()),
- (init_span.shrink_to_hi(), ")".to_string()),
- ],
- Applicability::MachineApplicable,
- )
- .emit();
+) -> &'a mut DiagnosticBuilder<'b, ()> {
+ lint.span_suggestion_verbose(
+ local.pat.span,
+ "consider binding to an unused variable to avoid immediately dropping the value",
+ "_unused",
+ Applicability::MachineApplicable,
+ )
+ .multipart_suggestion(
+ "consider immediately dropping the value",
+ vec![
+ (local.span.until(init_span), "drop(".to_string()),
+ (init_span.shrink_to_hi(), ")".to_string()),
+ ],
+ Applicability::MachineApplicable,
+ )
}
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 1e16ac51e..db0a3419e 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -3,13 +3,15 @@ use crate::late::unerased_lint_store;
use rustc_ast as ast;
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{Applicability, Diagnostic, LintDiagnosticBuilder, MultiSpan};
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, MultiSpan};
use rustc_hir as hir;
-use rustc_hir::{intravisit, HirId};
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::HirId;
+use rustc_index::vec::IndexVec;
use rustc_middle::hir::nested_filter;
use rustc_middle::lint::{
- struct_lint_level, LevelAndSource, LintExpectation, LintLevelMap, LintLevelSets,
- LintLevelSource, LintSet, LintStackIndex, COMMAND_LINE,
+ reveal_actual_level, struct_lint_level, LevelAndSource, LintExpectation, LintLevelSource,
+ ShallowLintLevelMap,
};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{RegisteredTools, TyCtxt};
@@ -27,47 +29,408 @@ use crate::errors::{
UnknownToolInScopedLint,
};
-fn lint_levels(tcx: TyCtxt<'_>, (): ()) -> LintLevelMap {
- let store = unerased_lint_store(tcx);
- let levels =
- LintLevelsBuilder::new(tcx.sess, false, &store, &tcx.resolutions(()).registered_tools);
- let mut builder = LintLevelMapBuilder { levels, tcx };
- let krate = tcx.hir().krate();
+/// Collection of lint levels for the whole crate.
+/// This is used by AST-based lints, which do not
+/// wait until we have built HIR to be emitted.
+#[derive(Debug)]
+struct LintLevelSets {
+ /// Linked list of specifications.
+ list: IndexVec<LintStackIndex, LintSet>,
+}
+
+rustc_index::newtype_index! {
+ struct LintStackIndex {
+ ENCODABLE = custom, // we don't need encoding
+ const COMMAND_LINE = 0,
+ }
+}
+
+/// Specifications found at this position in the stack. This map only represents the lints
+/// found for one set of attributes (like `shallow_lint_levels_on` does).
+///
+/// We store the level specifications as a linked list.
+/// Each `LintSet` represents a set of attributes on the same AST node.
+/// The `parent` forms a linked list that matches the AST tree.
+/// This way, walking the linked list is equivalent to walking the AST bottom-up
+/// to find the specifications for a given lint.
+#[derive(Debug)]
+struct LintSet {
+ // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
+ // flag.
+ specs: FxHashMap<LintId, LevelAndSource>,
+ parent: LintStackIndex,
+}
+
+impl LintLevelSets {
+ fn new() -> Self {
+ LintLevelSets { list: IndexVec::new() }
+ }
+
+ fn get_lint_level(
+ &self,
+ lint: &'static Lint,
+ idx: LintStackIndex,
+ aux: Option<&FxHashMap<LintId, LevelAndSource>>,
+ sess: &Session,
+ ) -> LevelAndSource {
+ let lint = LintId::of(lint);
+ let (level, mut src) = self.raw_lint_id_level(lint, idx, aux);
+ let level = reveal_actual_level(level, &mut src, sess, lint, |id| {
+ self.raw_lint_id_level(id, idx, aux)
+ });
+ (level, src)
+ }
- builder.levels.id_to_set.reserve(krate.owners.len() + 1);
+ fn raw_lint_id_level(
+ &self,
+ id: LintId,
+ mut idx: LintStackIndex,
+ aux: Option<&FxHashMap<LintId, LevelAndSource>>,
+ ) -> (Option<Level>, LintLevelSource) {
+ if let Some(specs) = aux {
+ if let Some(&(level, src)) = specs.get(&id) {
+ return (Some(level), src);
+ }
+ }
+ loop {
+ let LintSet { ref specs, parent } = self.list[idx];
+ if let Some(&(level, src)) = specs.get(&id) {
+ return (Some(level), src);
+ }
+ if idx == COMMAND_LINE {
+ return (None, LintLevelSource::Default);
+ }
+ idx = parent;
+ }
+ }
+}
- let push =
- builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), true, Some(hir::CRATE_HIR_ID));
+fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExpectation)> {
+ let store = unerased_lint_store(tcx);
- builder.levels.register_id(hir::CRATE_HIR_ID);
+ let mut builder = LintLevelsBuilder {
+ sess: tcx.sess,
+ provider: QueryMapExpectationsWrapper {
+ tcx,
+ cur: hir::CRATE_HIR_ID,
+ specs: ShallowLintLevelMap::default(),
+ expectations: Vec::new(),
+ unstable_to_stable_ids: FxHashMap::default(),
+ empty: FxHashMap::default(),
+ },
+ warn_about_weird_lints: false,
+ store,
+ registered_tools: &tcx.resolutions(()).registered_tools,
+ };
+
+ builder.add_command_line();
+ builder.add_id(hir::CRATE_HIR_ID);
tcx.hir().walk_toplevel_module(&mut builder);
- builder.levels.pop(push);
- builder.levels.update_unstable_expectation_ids();
- builder.levels.build_map()
+ tcx.sess.diagnostic().update_unstable_expectation_id(&builder.provider.unstable_to_stable_ids);
+
+ builder.provider.expectations
}
-pub struct LintLevelsBuilder<'s> {
- sess: &'s Session,
- lint_expectations: Vec<(LintExpectationId, LintExpectation)>,
- /// Each expectation has a stable and an unstable identifier. This map
- /// is used to map from unstable to stable [`LintExpectationId`]s.
- expectation_id_map: FxHashMap<LintExpectationId, LintExpectationId>,
+#[instrument(level = "trace", skip(tcx), ret)]
+fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLevelMap {
+ let store = unerased_lint_store(tcx);
+ let attrs = tcx.hir_attrs(owner);
+
+ let mut levels = LintLevelsBuilder {
+ sess: tcx.sess,
+ provider: LintLevelQueryMap {
+ tcx,
+ cur: owner.into(),
+ specs: ShallowLintLevelMap::default(),
+ empty: FxHashMap::default(),
+ attrs,
+ },
+ warn_about_weird_lints: false,
+ store,
+ registered_tools: &tcx.resolutions(()).registered_tools,
+ };
+
+ if owner == hir::CRATE_OWNER_ID {
+ levels.add_command_line();
+ }
+
+ match attrs.map.range(..) {
+ // There is only something to do if there are attributes at all.
+ [] => {}
+ // Most of the time, there is only one attribute. Avoid fetching HIR in that case.
+ [(local_id, _)] => levels.add_id(HirId { owner, local_id: *local_id }),
+ // Otherwise, we need to visit the attributes in source code order, so we fetch HIR and do
+ // a standard visit.
+ // FIXME(#102522) Just iterate on attrs once that iteration order matches HIR's.
+ _ => match tcx.hir().expect_owner(owner) {
+ hir::OwnerNode::Item(item) => levels.visit_item(item),
+ hir::OwnerNode::ForeignItem(item) => levels.visit_foreign_item(item),
+ hir::OwnerNode::TraitItem(item) => levels.visit_trait_item(item),
+ hir::OwnerNode::ImplItem(item) => levels.visit_impl_item(item),
+ hir::OwnerNode::Crate(mod_) => {
+ levels.add_id(hir::CRATE_HIR_ID);
+ levels.visit_mod(mod_, mod_.spans.inner_span, hir::CRATE_HIR_ID)
+ }
+ },
+ }
+
+ let specs = levels.provider.specs;
+
+ #[cfg(debug_assertions)]
+ for (_, v) in specs.specs.iter() {
+ debug_assert!(!v.is_empty());
+ }
+
+ specs
+}
+
+pub struct TopDown {
sets: LintLevelSets,
- id_to_set: FxHashMap<HirId, LintStackIndex>,
cur: LintStackIndex,
+}
+
+pub trait LintLevelsProvider {
+ fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource>;
+ fn insert(&mut self, id: LintId, lvl: LevelAndSource);
+ fn get_lint_level(&self, lint: &'static Lint, sess: &Session) -> LevelAndSource;
+ fn push_expectation(&mut self, _id: LintExpectationId, _expectation: LintExpectation) {}
+}
+
+impl LintLevelsProvider for TopDown {
+ fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> {
+ &self.sets.list[self.cur].specs
+ }
+
+ fn insert(&mut self, id: LintId, lvl: LevelAndSource) {
+ self.sets.list[self.cur].specs.insert(id, lvl);
+ }
+
+ fn get_lint_level(&self, lint: &'static Lint, sess: &Session) -> LevelAndSource {
+ self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), sess)
+ }
+}
+
+struct LintLevelQueryMap<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ cur: HirId,
+ specs: ShallowLintLevelMap,
+ /// Empty hash map to simplify code.
+ empty: FxHashMap<LintId, LevelAndSource>,
+ attrs: &'tcx hir::AttributeMap<'tcx>,
+}
+
+impl LintLevelsProvider for LintLevelQueryMap<'_> {
+ fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> {
+ self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty)
+ }
+ fn insert(&mut self, id: LintId, lvl: LevelAndSource) {
+ 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 {
+ self.specs.lint_level_id_at_node(self.tcx, LintId::of(lint), self.cur)
+ }
+}
+
+struct QueryMapExpectationsWrapper<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ cur: HirId,
+ specs: ShallowLintLevelMap,
+ expectations: Vec<(LintExpectationId, LintExpectation)>,
+ unstable_to_stable_ids: FxHashMap<LintExpectationId, LintExpectationId>,
+ /// Empty hash map to simplify code.
+ empty: FxHashMap<LintId, LevelAndSource>,
+}
+
+impl LintLevelsProvider for QueryMapExpectationsWrapper<'_> {
+ fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> {
+ 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);
+ }
+ fn get_lint_level(&self, lint: &'static Lint, _: &Session) -> LevelAndSource {
+ self.specs.lint_level_id_at_node(self.tcx, LintId::of(lint), self.cur)
+ }
+ fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation) {
+ let LintExpectationId::Stable { attr_id: Some(attr_id), hir_id, attr_index, .. } = id else { bug!("unstable expectation id should already be mapped") };
+ let key = LintExpectationId::Unstable { attr_id, lint_index: None };
+
+ if !self.unstable_to_stable_ids.contains_key(&key) {
+ self.unstable_to_stable_ids.insert(
+ key,
+ LintExpectationId::Stable { hir_id, attr_index, lint_index: None, attr_id: None },
+ );
+ }
+
+ self.expectations.push((id.normalize(), expectation));
+ }
+}
+
+impl<'tcx> LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
+ fn add_id(&mut self, hir_id: HirId) {
+ self.provider.cur = hir_id;
+ self.add(
+ self.provider.attrs.get(hir_id.local_id),
+ hir_id == hir::CRATE_HIR_ID,
+ Some(hir_id),
+ );
+ }
+}
+
+impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
+ type NestedFilter = nested_filter::OnlyBodies;
+
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.provider.tcx.hir()
+ }
+
+ fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
+ self.add_id(param.hir_id);
+ intravisit::walk_param(self, param);
+ }
+
+ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
+ self.add_id(it.hir_id());
+ intravisit::walk_item(self, it);
+ }
+
+ fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
+ self.add_id(it.hir_id());
+ intravisit::walk_foreign_item(self, it);
+ }
+
+ fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) {
+ // We will call `add_id` when we walk
+ // the `StmtKind`. The outer statement itself doesn't
+ // define the lint levels.
+ intravisit::walk_stmt(self, e);
+ }
+
+ fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
+ self.add_id(e.hir_id);
+ intravisit::walk_expr(self, e);
+ }
+
+ fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
+ self.add_id(s.hir_id);
+ intravisit::walk_field_def(self, s);
+ }
+
+ fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
+ self.add_id(v.id);
+ intravisit::walk_variant(self, v);
+ }
+
+ fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
+ self.add_id(l.hir_id);
+ intravisit::walk_local(self, l);
+ }
+
+ fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
+ self.add_id(a.hir_id);
+ intravisit::walk_arm(self, a);
+ }
+
+ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
+ self.add_id(trait_item.hir_id());
+ intravisit::walk_trait_item(self, trait_item);
+ }
+
+ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
+ self.add_id(impl_item.hir_id());
+ intravisit::walk_impl_item(self, impl_item);
+ }
+}
+
+impl<'tcx> LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'tcx>> {
+ fn add_id(&mut self, hir_id: HirId) {
+ self.provider.cur = hir_id;
+ self.add(self.provider.tcx.hir().attrs(hir_id), hir_id == hir::CRATE_HIR_ID, Some(hir_id));
+ }
+}
+
+impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'tcx>> {
+ type NestedFilter = nested_filter::All;
+
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.provider.tcx.hir()
+ }
+
+ fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
+ self.add_id(param.hir_id);
+ intravisit::walk_param(self, param);
+ }
+
+ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
+ self.add_id(it.hir_id());
+ intravisit::walk_item(self, it);
+ }
+
+ fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
+ self.add_id(it.hir_id());
+ intravisit::walk_foreign_item(self, it);
+ }
+
+ fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) {
+ // We will call `add_id` when we walk
+ // the `StmtKind`. The outer statement itself doesn't
+ // define the lint levels.
+ intravisit::walk_stmt(self, e);
+ }
+
+ fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
+ self.add_id(e.hir_id);
+ intravisit::walk_expr(self, e);
+ }
+
+ fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
+ self.add_id(s.hir_id);
+ intravisit::walk_field_def(self, s);
+ }
+
+ fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
+ self.add_id(v.id);
+ intravisit::walk_variant(self, v);
+ }
+
+ fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
+ self.add_id(l.hir_id);
+ intravisit::walk_local(self, l);
+ }
+
+ fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
+ self.add_id(a.hir_id);
+ intravisit::walk_arm(self, a);
+ }
+
+ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
+ self.add_id(trait_item.hir_id());
+ intravisit::walk_trait_item(self, trait_item);
+ }
+
+ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
+ self.add_id(impl_item.hir_id());
+ intravisit::walk_impl_item(self, impl_item);
+ }
+}
+
+pub struct LintLevelsBuilder<'s, P> {
+ sess: &'s Session,
+ provider: P,
warn_about_weird_lints: bool,
store: &'s LintStore,
registered_tools: &'s RegisteredTools,
}
-pub struct BuilderPush {
+pub(crate) struct BuilderPush {
prev: LintStackIndex,
- pub changed: bool,
}
-impl<'s> LintLevelsBuilder<'s> {
- pub fn new(
+impl<'s> LintLevelsBuilder<'s, TopDown> {
+ pub(crate) fn new(
sess: &'s Session,
warn_about_weird_lints: bool,
store: &'s LintStore,
@@ -75,20 +438,74 @@ impl<'s> LintLevelsBuilder<'s> {
) -> Self {
let mut builder = LintLevelsBuilder {
sess,
- lint_expectations: Default::default(),
- expectation_id_map: Default::default(),
- sets: LintLevelSets::new(),
- cur: COMMAND_LINE,
- id_to_set: Default::default(),
+ provider: TopDown { sets: LintLevelSets::new(), cur: COMMAND_LINE },
warn_about_weird_lints,
store,
registered_tools,
};
- builder.process_command_line(sess, store);
- assert_eq!(builder.sets.list.len(), 1);
+ builder.process_command_line();
+ assert_eq!(builder.provider.sets.list.len(), 1);
builder
}
+ fn process_command_line(&mut self) {
+ self.provider.cur = self
+ .provider
+ .sets
+ .list
+ .push(LintSet { specs: FxHashMap::default(), parent: COMMAND_LINE });
+ self.add_command_line();
+ }
+
+ /// Pushes a list of AST lint attributes onto this context.
+ ///
+ /// This function will return a `BuilderPush` object which should be passed
+ /// to `pop` when this scope for the attributes provided is exited.
+ ///
+ /// This function will perform a number of tasks:
+ ///
+ /// * It'll validate all lint-related attributes in `attrs`
+ /// * It'll mark all lint-related attributes as used
+ /// * Lint levels will be updated based on the attributes provided
+ /// * Lint attributes are validated, e.g., a `#[forbid]` can't be switched to
+ /// `#[allow]`
+ ///
+ /// Don't forget to call `pop`!
+ pub(crate) fn push(
+ &mut self,
+ attrs: &[ast::Attribute],
+ is_crate_node: bool,
+ source_hir_id: Option<HirId>,
+ ) -> BuilderPush {
+ let prev = self.provider.cur;
+ self.provider.cur =
+ self.provider.sets.list.push(LintSet { specs: FxHashMap::default(), parent: prev });
+
+ self.add(attrs, is_crate_node, source_hir_id);
+
+ if self.provider.current_specs().is_empty() {
+ self.provider.sets.list.pop();
+ self.provider.cur = prev;
+ }
+
+ BuilderPush { prev }
+ }
+
+ /// Called after `push` when the scope of a set of attributes are exited.
+ pub(crate) fn pop(&mut self, push: BuilderPush) {
+ self.provider.cur = push.prev;
+ std::mem::forget(push);
+ }
+}
+
+#[cfg(debug_assertions)]
+impl Drop for BuilderPush {
+ fn drop(&mut self) {
+ panic!("Found a `push` without a `pop`.");
+ }
+}
+
+impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
pub(crate) fn sess(&self) -> &Session {
self.sess
}
@@ -98,24 +515,20 @@ impl<'s> LintLevelsBuilder<'s> {
}
fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> {
- &self.sets.list[self.cur].specs
+ self.provider.current_specs()
}
- fn current_specs_mut(&mut self) -> &mut FxHashMap<LintId, LevelAndSource> {
- &mut self.sets.list[self.cur].specs
+ fn insert(&mut self, id: LintId, lvl: LevelAndSource) {
+ self.provider.insert(id, lvl)
}
- fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
- self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
-
- self.cur =
- self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: COMMAND_LINE });
- for &(ref lint_name, level) in &sess.opts.lint_opts {
- store.check_lint_name_cmdline(sess, &lint_name, level, self.registered_tools);
+ fn add_command_line(&mut self) {
+ for &(ref lint_name, level) in &self.sess.opts.lint_opts {
+ self.store.check_lint_name_cmdline(self.sess, &lint_name, level, self.registered_tools);
let orig_level = level;
let lint_flag_val = Symbol::intern(lint_name);
- let Ok(ids) = store.find_lints(&lint_name) else {
+ let Ok(ids) = self.store.find_lints(&lint_name) else {
// errors handled in check_lint_name_cmdline above
continue
};
@@ -129,7 +542,7 @@ impl<'s> LintLevelsBuilder<'s> {
if self.check_gated_lint(id, DUMMY_SP) {
let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
- self.current_specs_mut().insert(id, (level, src));
+ self.insert(id, (level, src));
}
}
}
@@ -138,9 +551,11 @@ impl<'s> LintLevelsBuilder<'s> {
/// Attempts to insert the `id` to `level_src` map entry. If unsuccessful
/// (e.g. if a forbid was already inserted on the same scope), then emits a
/// diagnostic with no change to `specs`.
- fn insert_spec(&mut self, id: LintId, (level, src): LevelAndSource) {
- let (old_level, old_src) =
- self.sets.get_lint_level(id.lint, self.cur, Some(self.current_specs()), &self.sess);
+ fn insert_spec(&mut self, id: LintId, (mut level, src): LevelAndSource) {
+ let (old_level, old_src) = self.provider.get_lint_level(id.lint, &self.sess);
+ if let Level::Expect(id) = &mut level && let LintExpectationId::Stable { .. } = id {
+ *id = id.normalize();
+ }
// Setting to a non-forbid level is an error if the lint previously had
// a forbid level. Note that this is not necessarily true even with a
// `#[forbid(..)]` attribute present, as that is overridden by `--cap-lints`.
@@ -158,7 +573,7 @@ impl<'s> LintLevelsBuilder<'s> {
let id_name = id.lint.name_lower();
let fcw_warning = match old_src {
LintLevelSource::Default => false,
- LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol),
+ LintLevelSource::Node { name, .. } => self.store.is_lint_group(name),
LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol),
};
debug!(
@@ -178,8 +593,8 @@ impl<'s> LintLevelsBuilder<'s> {
id.to_string()
));
}
- LintLevelSource::Node(_, forbid_source_span, reason) => {
- diag.span_label(forbid_source_span, "`forbid` level set here");
+ LintLevelSource::Node { span, reason, .. } => {
+ diag.span_label(span, "`forbid` level set here");
if let Some(rationale) = reason {
diag.note(rationale.as_str());
}
@@ -199,11 +614,8 @@ impl<'s> LintLevelsBuilder<'s> {
LintLevelSource::Default => {
OverruledAttributeSub::DefaultSource { id: id.to_string() }
}
- LintLevelSource::Node(_, forbid_source_span, reason) => {
- OverruledAttributeSub::NodeSource {
- span: forbid_source_span,
- reason,
- }
+ LintLevelSource::Node { span, reason, .. } => {
+ OverruledAttributeSub::NodeSource { span, reason }
}
LintLevelSource::CommandLine(_, _) => {
OverruledAttributeSub::CommandLineSource
@@ -214,14 +626,14 @@ impl<'s> LintLevelsBuilder<'s> {
self.struct_lint(
FORBIDDEN_LINT_GROUPS,
Some(src.span().into()),
- |diag_builder| {
- let mut diag_builder = diag_builder.build(&format!(
- "{}({}) incompatible with previous forbid",
- level.as_str(),
- src.name(),
- ));
- decorate_diag(&mut diag_builder);
- diag_builder.emit();
+ format!(
+ "{}({}) incompatible with previous forbid",
+ level.as_str(),
+ src.name(),
+ ),
+ |lint| {
+ decorate_diag(lint);
+ lint
},
);
}
@@ -244,45 +656,21 @@ impl<'s> LintLevelsBuilder<'s> {
match (old_level, level) {
// If the new level is an expectation store it in `ForceWarn`
- (Level::ForceWarn(_), Level::Expect(expectation_id)) => self
- .current_specs_mut()
- .insert(id, (Level::ForceWarn(Some(expectation_id)), old_src)),
- // Keep `ForceWarn` level but drop the expectation
- (Level::ForceWarn(_), _) => {
- self.current_specs_mut().insert(id, (Level::ForceWarn(None), old_src))
+ (Level::ForceWarn(_), Level::Expect(expectation_id)) => {
+ self.insert(id, (Level::ForceWarn(Some(expectation_id)), old_src))
}
+ // Keep `ForceWarn` level but drop the expectation
+ (Level::ForceWarn(_), _) => self.insert(id, (Level::ForceWarn(None), old_src)),
// Set the lint level as normal
- _ => self.current_specs_mut().insert(id, (level, src)),
+ _ => self.insert(id, (level, src)),
};
}
- /// Pushes a list of AST lint attributes onto this context.
- ///
- /// This function will return a `BuilderPush` object which should be passed
- /// to `pop` when this scope for the attributes provided is exited.
- ///
- /// This function will perform a number of tasks:
- ///
- /// * It'll validate all lint-related attributes in `attrs`
- /// * It'll mark all lint-related attributes as used
- /// * Lint levels will be updated based on the attributes provided
- /// * Lint attributes are validated, e.g., a `#[forbid]` can't be switched to
- /// `#[allow]`
- ///
- /// Don't forget to call `pop`!
- pub(crate) fn push(
- &mut self,
- attrs: &[ast::Attribute],
- is_crate_node: bool,
- source_hir_id: Option<HirId>,
- ) -> BuilderPush {
- let prev = self.cur;
- self.cur = self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: prev });
-
+ fn add(&mut self, attrs: &[ast::Attribute], is_crate_node: bool, source_hir_id: Option<HirId>) {
let sess = self.sess;
for (attr_index, attr) in attrs.iter().enumerate() {
if attr.has_name(sym::automatically_derived) {
- self.current_specs_mut().insert(
+ self.insert(
LintId::of(SINGLE_USE_LIFETIMES),
(Level::Allow, LintLevelSource::Default),
);
@@ -293,7 +681,17 @@ impl<'s> LintLevelsBuilder<'s> {
None => continue,
// This is the only lint level with a `LintExpectationId` that can be created from an attribute
Some(Level::Expect(unstable_id)) if let Some(hir_id) = source_hir_id => {
- let stable_id = self.create_stable_id(unstable_id, hir_id, attr_index);
+ let LintExpectationId::Unstable { attr_id, lint_index } = unstable_id
+ else { bug!("stable id Level::from_attr") };
+
+ let stable_id = LintExpectationId::Stable {
+ hir_id,
+ attr_index: attr_index.try_into().unwrap(),
+ lint_index,
+ // we pass the previous unstable attr_id such that we can trace the ast id when building a map
+ // to go from unstable to stable id.
+ attr_id: Some(attr_id),
+ };
Level::Expect(stable_id)
}
@@ -408,7 +806,7 @@ impl<'s> LintLevelsBuilder<'s> {
[lint] => *lint == LintId::of(UNFULFILLED_LINT_EXPECTATIONS),
_ => false,
};
- self.lint_expectations.push((
+ self.provider.push_expectation(
expect_id,
LintExpectation::new(
reason,
@@ -416,13 +814,19 @@ impl<'s> LintLevelsBuilder<'s> {
is_unfulfilled_lint_expectations,
tool_name,
),
- ));
+ );
}
- let src = LintLevelSource::Node(
- meta_item.path.segments.last().expect("empty lint name").ident.name,
- sp,
+ let src = LintLevelSource::Node {
+ name: meta_item
+ .path
+ .segments
+ .last()
+ .expect("empty lint name")
+ .ident
+ .name,
+ span: sp,
reason,
- );
+ };
for &id in *ids {
if self.check_gated_lint(id, attr.span) {
self.insert_spec(id, (level, src));
@@ -435,67 +839,60 @@ impl<'s> LintLevelsBuilder<'s> {
Ok(ids) => {
let complete_name =
&format!("{}::{}", tool_ident.unwrap().name, name);
- let src = LintLevelSource::Node(
- Symbol::intern(complete_name),
- sp,
+ let src = LintLevelSource::Node {
+ name: Symbol::intern(complete_name),
+ span: sp,
reason,
- );
+ };
for &id in ids {
if self.check_gated_lint(id, attr.span) {
self.insert_spec(id, (level, src));
}
}
if let Level::Expect(expect_id) = level {
- self.lint_expectations.push((
+ self.provider.push_expectation(
expect_id,
LintExpectation::new(reason, sp, false, tool_name),
- ));
+ );
}
}
Err((Some(ids), ref new_lint_name)) => {
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
- let (lvl, src) = self.sets.get_lint_level(
- lint,
- self.cur,
- Some(self.current_specs()),
- &sess,
- );
+ let (lvl, src) = self.provider.get_lint_level(lint, &sess);
struct_lint_level(
self.sess,
lint,
lvl,
src,
Some(sp.into()),
+ format!(
+ "lint name `{}` is deprecated \
+ and may not have an effect in the future.",
+ name
+ ),
|lint| {
- let msg = format!(
- "lint name `{}` is deprecated \
- and may not have an effect in the future.",
- name
- );
- lint.build(&msg)
- .span_suggestion(
- sp,
- "change it to",
- new_lint_name,
- Applicability::MachineApplicable,
- )
- .emit();
+ lint.span_suggestion(
+ sp,
+ "change it to",
+ new_lint_name,
+ Applicability::MachineApplicable,
+ )
},
);
- let src = LintLevelSource::Node(
- Symbol::intern(&new_lint_name),
- sp,
+ let src = LintLevelSource::Node {
+ name: Symbol::intern(&new_lint_name),
+ span: sp,
reason,
- );
+ };
for id in ids {
self.insert_spec(*id, (level, src));
}
if let Level::Expect(expect_id) = level {
- self.lint_expectations.push((
+ self.provider.push_expectation(
expect_id,
LintExpectation::new(reason, sp, false, tool_name),
- ));
+ );
}
}
Err((None, _)) => {
@@ -521,57 +918,54 @@ impl<'s> LintLevelsBuilder<'s> {
CheckLintNameResult::Warning(msg, renamed) => {
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
- let (renamed_lint_level, src) = self.sets.get_lint_level(
- lint,
- self.cur,
- Some(self.current_specs()),
- &sess,
- );
+ let (renamed_lint_level, src) = self.provider.get_lint_level(lint, &sess);
struct_lint_level(
self.sess,
lint,
renamed_lint_level,
src,
Some(sp.into()),
+ msg,
|lint| {
- let mut err = lint.build(msg);
if let Some(new_name) = &renamed {
- err.span_suggestion(
+ lint.span_suggestion(
sp,
"use the new name",
new_name,
Applicability::MachineApplicable,
);
}
- err.emit();
+ lint
},
);
}
CheckLintNameResult::NoLint(suggestion) => {
let lint = builtin::UNKNOWN_LINTS;
- let (level, src) = self.sets.get_lint_level(
- lint,
- self.cur,
- Some(self.current_specs()),
+ let (level, src) = self.provider.get_lint_level(lint, self.sess);
+ let name = if let Some(tool_ident) = tool_ident {
+ format!("{}::{}", tool_ident.name, name)
+ } else {
+ name.to_string()
+ };
+ struct_lint_level(
self.sess,
+ lint,
+ level,
+ src,
+ Some(sp.into()),
+ format!("unknown lint: `{}`", name),
+ |lint| {
+ if let Some(suggestion) = suggestion {
+ lint.span_suggestion(
+ sp,
+ "did you mean",
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ lint
+ },
);
- struct_lint_level(self.sess, lint, level, src, Some(sp.into()), |lint| {
- let name = if let Some(tool_ident) = tool_ident {
- format!("{}::{}", tool_ident.name, name)
- } else {
- name.to_string()
- };
- let mut db = lint.build(format!("unknown lint: `{}`", name));
- if let Some(suggestion) = suggestion {
- db.span_suggestion(
- sp,
- "did you mean",
- suggestion,
- Applicability::MachineApplicable,
- );
- }
- db.emit();
- });
}
}
// If this lint was renamed, apply the new lint instead of ignoring the attribute.
@@ -583,17 +977,21 @@ impl<'s> LintLevelsBuilder<'s> {
if let CheckLintNameResult::Ok(ids) =
self.store.check_lint_name(&new_name, None, self.registered_tools)
{
- let src = LintLevelSource::Node(Symbol::intern(&new_name), sp, reason);
+ let src = LintLevelSource::Node {
+ name: Symbol::intern(&new_name),
+ span: sp,
+ reason,
+ };
for &id in ids {
if self.check_gated_lint(id, attr.span) {
self.insert_spec(id, (level, src));
}
}
if let Level::Expect(expect_id) = level {
- self.lint_expectations.push((
+ self.provider.push_expectation(
expect_id,
LintExpectation::new(reason, sp, false, tool_name),
- ));
+ );
}
} else {
panic!("renamed lint does not exist: {}", new_name);
@@ -608,232 +1006,87 @@ impl<'s> LintLevelsBuilder<'s> {
continue;
}
- let LintLevelSource::Node(lint_attr_name, lint_attr_span, _) = *src else {
+ let LintLevelSource::Node { name: lint_attr_name, span: lint_attr_span, .. } = *src else {
continue
};
let lint = builtin::UNUSED_ATTRIBUTES;
- let (lint_level, lint_src) =
- self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), self.sess);
+ let (lint_level, lint_src) = self.provider.get_lint_level(lint, &self.sess);
struct_lint_level(
self.sess,
lint,
lint_level,
lint_src,
Some(lint_attr_span.into()),
- |lint| {
- let mut db = lint.build(&format!(
- "{}({}) is ignored unless specified at crate level",
- level.as_str(),
- lint_attr_name
- ));
- db.emit();
- },
+ format!(
+ "{}({}) is ignored unless specified at crate level",
+ level.as_str(),
+ lint_attr_name
+ ),
+ |lint| lint,
);
// don't set a separate error for every lint in the group
break;
}
}
-
- if self.current_specs().is_empty() {
- self.sets.list.pop();
- self.cur = prev;
- }
-
- BuilderPush { prev, changed: prev != self.cur }
- }
-
- fn create_stable_id(
- &mut self,
- unstable_id: LintExpectationId,
- hir_id: HirId,
- attr_index: usize,
- ) -> LintExpectationId {
- let stable_id =
- LintExpectationId::Stable { hir_id, attr_index: attr_index as u16, lint_index: None };
-
- self.expectation_id_map.insert(unstable_id, stable_id);
-
- stable_id
}
/// Checks if the lint is gated on a feature that is not enabled.
///
/// Returns `true` if the lint's feature is enabled.
+ // FIXME only emit this once for each attribute, instead of repeating it 4 times for
+ // pre-expansion lints, post-expansion lints, `shallow_lint_levels_on` and `lint_expectations`.
fn check_gated_lint(&self, lint_id: LintId, span: Span) -> bool {
if let Some(feature) = lint_id.lint.feature_gate {
if !self.sess.features_untracked().enabled(feature) {
let lint = builtin::UNKNOWN_LINTS;
let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
- struct_lint_level(self.sess, lint, level, src, Some(span.into()), |lint_db| {
- let mut db =
- lint_db.build(&format!("unknown lint: `{}`", lint_id.lint.name_lower()));
- db.note(&format!("the `{}` lint is unstable", lint_id.lint.name_lower(),));
- add_feature_diagnostics(&mut db, &self.sess.parse_sess, feature);
- db.emit();
- });
+ struct_lint_level(
+ self.sess,
+ lint,
+ level,
+ src,
+ Some(span.into()),
+ format!("unknown lint: `{}`", lint_id.lint.name_lower()),
+ |lint| {
+ lint.note(
+ &format!("the `{}` lint is unstable", lint_id.lint.name_lower(),),
+ );
+ add_feature_diagnostics(lint, &self.sess.parse_sess, feature);
+ lint
+ },
+ );
return false;
}
}
true
}
- /// Called after `push` when the scope of a set of attributes are exited.
- pub fn pop(&mut self, push: BuilderPush) {
- self.cur = push.prev;
- }
-
/// Find the lint level for a lint.
- pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintLevelSource) {
- self.sets.get_lint_level(lint, self.cur, None, self.sess)
+ pub fn lint_level(&self, lint: &'static Lint) -> LevelAndSource {
+ self.provider.get_lint_level(lint, self.sess)
}
/// Used to emit a lint-related diagnostic based on the current state of
/// this lint context.
- pub fn struct_lint(
+ ///
+ /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+ ///
+ /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
+ pub(crate) fn struct_lint(
&self,
lint: &'static Lint,
span: Option<MultiSpan>,
- decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+ msg: impl Into<DiagnosticMessage>,
+ decorate: impl for<'a, 'b> FnOnce(
+ &'b mut DiagnosticBuilder<'a, ()>,
+ ) -> &'b mut DiagnosticBuilder<'a, ()>,
) {
let (level, src) = self.lint_level(lint);
- struct_lint_level(self.sess, lint, level, src, span, decorate)
- }
-
- /// Registers the ID provided with the current set of lints stored in
- /// this context.
- pub fn register_id(&mut self, id: HirId) {
- self.id_to_set.insert(id, self.cur);
- }
-
- fn update_unstable_expectation_ids(&self) {
- self.sess.diagnostic().update_unstable_expectation_id(&self.expectation_id_map);
- }
-
- pub fn build_map(self) -> LintLevelMap {
- LintLevelMap {
- sets: self.sets,
- id_to_set: self.id_to_set,
- lint_expectations: self.lint_expectations,
- }
- }
-}
-
-struct LintLevelMapBuilder<'tcx> {
- levels: LintLevelsBuilder<'tcx>,
- tcx: TyCtxt<'tcx>,
-}
-
-impl LintLevelMapBuilder<'_> {
- fn with_lint_attrs<F>(&mut self, id: hir::HirId, f: F)
- where
- F: FnOnce(&mut Self),
- {
- let is_crate_hir = id == hir::CRATE_HIR_ID;
- let attrs = self.tcx.hir().attrs(id);
- let push = self.levels.push(attrs, is_crate_hir, Some(id));
-
- if push.changed {
- self.levels.register_id(id);
- }
- f(self);
- self.levels.pop(push);
- }
-}
-
-impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> {
- type NestedFilter = nested_filter::All;
-
- fn nested_visit_map(&mut self) -> Self::Map {
- self.tcx.hir()
- }
-
- fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
- self.with_lint_attrs(param.hir_id, |builder| {
- intravisit::walk_param(builder, param);
- });
- }
-
- fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
- self.with_lint_attrs(it.hir_id(), |builder| {
- intravisit::walk_item(builder, it);
- });
- }
-
- fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
- self.with_lint_attrs(it.hir_id(), |builder| {
- intravisit::walk_foreign_item(builder, it);
- })
- }
-
- fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) {
- // We will call `with_lint_attrs` when we walk
- // the `StmtKind`. The outer statement itself doesn't
- // define the lint levels.
- intravisit::walk_stmt(self, e);
- }
-
- fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
- self.with_lint_attrs(e.hir_id, |builder| {
- intravisit::walk_expr(builder, e);
- })
- }
-
- fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) {
- self.with_lint_attrs(field.hir_id, |builder| {
- intravisit::walk_expr_field(builder, field);
- })
- }
-
- fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
- self.with_lint_attrs(s.hir_id, |builder| {
- intravisit::walk_field_def(builder, s);
- })
- }
-
- fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
- self.with_lint_attrs(v.id, |builder| {
- intravisit::walk_variant(builder, v);
- })
- }
-
- fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
- self.with_lint_attrs(l.hir_id, |builder| {
- intravisit::walk_local(builder, l);
- })
- }
-
- fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
- self.with_lint_attrs(a.hir_id, |builder| {
- intravisit::walk_arm(builder, a);
- })
- }
-
- fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
- self.with_lint_attrs(trait_item.hir_id(), |builder| {
- intravisit::walk_trait_item(builder, trait_item);
- });
- }
-
- fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
- self.with_lint_attrs(impl_item.hir_id(), |builder| {
- intravisit::walk_impl_item(builder, impl_item);
- });
- }
-
- fn visit_pat_field(&mut self, field: &'tcx hir::PatField<'tcx>) {
- self.with_lint_attrs(field.hir_id, |builder| {
- intravisit::walk_pat_field(builder, field);
- })
- }
-
- fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
- self.with_lint_attrs(p.hir_id, |builder| {
- intravisit::walk_generic_param(builder, p);
- });
+ struct_lint_level(self.sess, lint, level, src, span, msg, decorate)
}
}
-pub fn provide(providers: &mut Providers) {
- providers.lint_levels = lint_levels;
+pub(crate) fn provide(providers: &mut Providers) {
+ *providers = Providers { shallow_lint_levels_on, lint_expectations, ..*providers };
}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 752a751f6..5288fc542 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -34,7 +34,7 @@
#![feature(iter_intersperse)]
#![feature(iter_order_by)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
+#![feature(min_specialization)]
#![feature(never_type)]
#![recursion_limit = "256"]
@@ -52,6 +52,7 @@ mod early;
mod enum_intrinsics_non_enums;
mod errors;
mod expect;
+mod for_loops_over_fallibles;
pub mod hidden_unicode_codepoints;
mod internal;
mod late;
@@ -62,6 +63,7 @@ mod non_ascii_idents;
mod non_fmt_panic;
mod nonstandard_style;
mod noop_method_call;
+mod opaque_hidden_inferred_bound;
mod pass_by_value;
mod passes;
mod redundant_semicolon;
@@ -85,6 +87,7 @@ use rustc_span::Span;
use array_into_iter::ArrayIntoIter;
use builtin::*;
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
+use for_loops_over_fallibles::*;
use hidden_unicode_codepoints::*;
use internal::*;
use let_underscore::*;
@@ -93,6 +96,7 @@ use non_ascii_idents::*;
use non_fmt_panic::NonPanicFmt;
use nonstandard_style::*;
use noop_method_call::*;
+use opaque_hidden_inferred_bound::*;
use pass_by_value::*;
use redundant_semicolon::*;
use traits::*;
@@ -186,6 +190,7 @@ macro_rules! late_lint_mod_passes {
$macro!(
$args,
[
+ ForLoopsOverFallibles: ForLoopsOverFallibles,
HardwiredLints: HardwiredLints,
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
ImproperCTypesDefinitions: ImproperCTypesDefinitions,
@@ -207,7 +212,7 @@ macro_rules! late_lint_mod_passes {
TypeLimits: TypeLimits::new(),
NonSnakeCase: NonSnakeCase,
InvalidNoMangleItems: InvalidNoMangleItems,
- // Depends on access levels
+ // Depends on effective visibilities
UnreachablePub: UnreachablePub,
ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
InvalidValue: InvalidValue,
@@ -223,6 +228,7 @@ macro_rules! late_lint_mod_passes {
EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
InvalidAtomicOrdering: InvalidAtomicOrdering,
NamedAsmLabels: NamedAsmLabels,
+ OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
]
);
};
@@ -519,6 +525,11 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
"now allowed, see issue #59159 \
<https://github.com/rust-lang/rust/issues/59159> for more information",
);
+ store.register_removed(
+ "const_err",
+ "converted into hard error, see issue #71800 \
+ <https://github.com/rust-lang/rust/issues/71800> for more information",
+ );
}
fn register_internals(store: &mut LintStore) {
diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs
index 5f7f03480..e2d7d5b49 100644
--- a/compiler/rustc_lint/src/methods.rs
+++ b/compiler/rustc_lint/src/methods.rs
@@ -90,14 +90,17 @@ fn lint_cstring_as_ptr(
if cx.tcx.is_diagnostic_item(sym::Result, def.did()) {
if let ty::Adt(adt, _) = substs.type_at(0).kind() {
if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) {
- cx.struct_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, |diag| {
- diag.build(fluent::lint::cstring_ptr)
- .span_label(as_ptr_span, fluent::lint::as_ptr_label)
- .span_label(unwrap.span, fluent::lint::unwrap_label)
- .note(fluent::lint::note)
- .help(fluent::lint::help)
- .emit();
- });
+ cx.struct_span_lint(
+ TEMPORARY_CSTRING_AS_PTR,
+ as_ptr_span,
+ fluent::lint_cstring_ptr,
+ |diag| {
+ diag.span_label(as_ptr_span, fluent::as_ptr_label)
+ .span_label(unwrap.span, fluent::unwrap_label)
+ .note(fluent::note)
+ .help(fluent::help)
+ },
+ );
}
}
}
diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs
index 764003e61..dea9506ac 100644
--- a/compiler/rustc_lint/src/non_ascii_idents.rs
+++ b/compiler/rustc_lint/src/non_ascii_idents.rs
@@ -180,15 +180,21 @@ impl EarlyLintPass for NonAsciiIdents {
continue;
}
has_non_ascii_idents = true;
- cx.struct_span_lint(NON_ASCII_IDENTS, sp, |lint| {
- lint.build(fluent::lint::identifier_non_ascii_char).emit();
- });
+ cx.struct_span_lint(
+ NON_ASCII_IDENTS,
+ sp,
+ fluent::lint_identifier_non_ascii_char,
+ |lint| lint,
+ );
if check_uncommon_codepoints
&& !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed)
{
- cx.struct_span_lint(UNCOMMON_CODEPOINTS, sp, |lint| {
- lint.build(fluent::lint::identifier_uncommon_codepoints).emit();
- })
+ cx.struct_span_lint(
+ UNCOMMON_CODEPOINTS,
+ sp,
+ fluent::lint_identifier_uncommon_codepoints,
+ |lint| lint,
+ )
}
}
@@ -216,13 +222,16 @@ impl EarlyLintPass for NonAsciiIdents {
.entry(skeleton_sym)
.and_modify(|(existing_symbol, existing_span, existing_is_ascii)| {
if !*existing_is_ascii || !is_ascii {
- cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| {
- lint.build(fluent::lint::confusable_identifier_pair)
- .set_arg("existing_sym", *existing_symbol)
- .set_arg("sym", symbol)
- .span_label(*existing_span, fluent::lint::label)
- .emit();
- });
+ cx.struct_span_lint(
+ CONFUSABLE_IDENTS,
+ sp,
+ fluent::lint_confusable_identifier_pair,
+ |lint| {
+ lint.set_arg("existing_sym", *existing_symbol)
+ .set_arg("sym", symbol)
+ .span_label(*existing_span, fluent::label)
+ },
+ );
}
if *existing_is_ascii && !is_ascii {
*existing_symbol = symbol;
@@ -322,22 +331,25 @@ impl EarlyLintPass for NonAsciiIdents {
}
for ((sp, ch_list), script_set) in lint_reports {
- cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| {
- let mut includes = String::new();
- for (idx, ch) in ch_list.into_iter().enumerate() {
- if idx != 0 {
- includes += ", ";
+ cx.struct_span_lint(
+ MIXED_SCRIPT_CONFUSABLES,
+ sp,
+ fluent::lint_mixed_script_confusables,
+ |lint| {
+ let mut includes = String::new();
+ for (idx, ch) in ch_list.into_iter().enumerate() {
+ if idx != 0 {
+ includes += ", ";
+ }
+ let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
+ includes += &char_info;
}
- let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
- includes += &char_info;
- }
- lint.build(fluent::lint::mixed_script_confusables)
- .set_arg("set", script_set.to_string())
- .set_arg("includes", includes)
- .note(fluent::lint::includes_note)
- .note(fluent::lint::note)
- .emit();
- });
+ lint.set_arg("set", script_set.to_string())
+ .set_arg("includes", includes)
+ .note(fluent::includes_note)
+ .note(fluent::note)
+ },
+ );
}
}
}
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index cdad2d2e8..6ad2e0294 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -119,22 +119,20 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
arg_span = expn.call_site;
}
- cx.struct_span_lint(NON_FMT_PANICS, arg_span, |lint| {
- let mut l = lint.build(fluent::lint::non_fmt_panic);
- l.set_arg("name", symbol);
- l.note(fluent::lint::note);
- l.note(fluent::lint::more_info_note);
+ cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint_non_fmt_panic, |lint| {
+ lint.set_arg("name", symbol);
+ lint.note(fluent::note);
+ lint.note(fluent::more_info_note);
if !is_arg_inside_call(arg_span, span) {
// No clue where this argument is coming from.
- l.emit();
- return;
+ return lint;
}
if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
// A case of `panic!(format!(..))`.
- l.note(fluent::lint::supports_fmt_note);
+ lint.note(fluent::supports_fmt_note);
if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
- l.multipart_suggestion(
- fluent::lint::supports_fmt_suggestion,
+ lint.multipart_suggestion(
+ fluent::supports_fmt_suggestion,
vec![
(arg_span.until(open.shrink_to_hi()), "".into()),
(close.until(arg_span.shrink_to_hi()), "".into()),
@@ -153,21 +151,19 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
Some(ty_def) if cx.tcx.is_diagnostic_item(sym::String, ty_def.did()),
);
- let (suggest_display, suggest_debug) = cx.tcx.infer_ctxt().enter(|infcx| {
- let display = is_str
- || cx.tcx.get_diagnostic_item(sym::Display).map(|t| {
- infcx
- .type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
- .may_apply()
- }) == Some(true);
- let debug = !display
- && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| {
- infcx
- .type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
- .may_apply()
- }) == Some(true);
- (display, debug)
- });
+ let infcx = cx.tcx.infer_ctxt().build();
+ let suggest_display = is_str
+ || cx.tcx.get_diagnostic_item(sym::Display).map(|t| {
+ infcx
+ .type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
+ .may_apply()
+ }) == Some(true);
+ let suggest_debug = !suggest_display
+ && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| {
+ infcx
+ .type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
+ .may_apply()
+ }) == Some(true);
let suggest_panic_any = !is_str && panic == sym::std_panic_macro;
@@ -180,17 +176,17 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
};
if suggest_display {
- l.span_suggestion_verbose(
+ lint.span_suggestion_verbose(
arg_span.shrink_to_lo(),
- fluent::lint::display_suggestion,
+ fluent::display_suggestion,
"\"{}\", ",
fmt_applicability,
);
} else if suggest_debug {
- l.set_arg("ty", ty);
- l.span_suggestion_verbose(
+ lint.set_arg("ty", ty);
+ lint.span_suggestion_verbose(
arg_span.shrink_to_lo(),
- fluent::lint::debug_suggestion,
+ fluent::debug_suggestion,
"\"{:?}\", ",
fmt_applicability,
);
@@ -198,9 +194,9 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
if suggest_panic_any {
if let Some((open, close, del)) = find_delimiters(cx, span) {
- l.set_arg("already_suggested", suggest_display || suggest_debug);
- l.multipart_suggestion(
- fluent::lint::panic_suggestion,
+ lint.set_arg("already_suggested", suggest_display || suggest_debug);
+ lint.multipart_suggestion(
+ fluent::panic_suggestion,
if del == '(' {
vec![(span.until(open), "std::panic::panic_any".into())]
} else {
@@ -214,7 +210,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
}
}
}
- l.emit();
+ lint
});
}
@@ -258,25 +254,24 @@ fn check_panic_str<'tcx>(
.map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
.collect(),
};
- cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| {
- let mut l = lint.build(fluent::lint::non_fmt_panic_unused);
- l.set_arg("count", n_arguments);
- l.note(fluent::lint::note);
+ cx.struct_span_lint(NON_FMT_PANICS, arg_spans, fluent::lint_non_fmt_panic_unused, |lint| {
+ lint.set_arg("count", n_arguments);
+ lint.note(fluent::note);
if is_arg_inside_call(arg.span, span) {
- l.span_suggestion(
+ lint.span_suggestion(
arg.span.shrink_to_hi(),
- fluent::lint::add_args_suggestion,
+ fluent::add_args_suggestion,
", ...",
Applicability::HasPlaceholders,
);
- l.span_suggestion(
+ lint.span_suggestion(
arg.span.shrink_to_lo(),
- fluent::lint::add_fmt_suggestion,
+ fluent::add_fmt_suggestion,
"\"{}\", ",
Applicability::MachineApplicable,
);
}
- l.emit();
+ lint
});
} else {
let brace_spans: Option<Vec<_>> =
@@ -287,20 +282,24 @@ fn check_panic_str<'tcx>(
.collect()
});
let count = brace_spans.as_ref().map(|v| v.len()).unwrap_or(/* any number >1 */ 2);
- cx.struct_span_lint(NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), |lint| {
- let mut l = lint.build(fluent::lint::non_fmt_panic_braces);
- l.set_arg("count", count);
- l.note(fluent::lint::note);
- if is_arg_inside_call(arg.span, span) {
- l.span_suggestion(
- arg.span.shrink_to_lo(),
- fluent::lint::suggestion,
- "\"{}\", ",
- Applicability::MachineApplicable,
- );
- }
- l.emit();
- });
+ cx.struct_span_lint(
+ NON_FMT_PANICS,
+ brace_spans.unwrap_or_else(|| vec![span]),
+ fluent::lint_non_fmt_panic_braces,
+ |lint| {
+ lint.set_arg("count", count);
+ lint.note(fluent::note);
+ if is_arg_inside_call(arg.span, span) {
+ lint.span_suggestion(
+ arg.span.shrink_to_lo(),
+ fluent::suggestion,
+ "\"{}\", ",
+ Applicability::MachineApplicable,
+ );
+ }
+ lint
+ },
+ );
}
}
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 768ad8483..7e50801f8 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -136,26 +136,30 @@ impl NonCamelCaseTypes {
let name = ident.name.as_str();
if !is_camel_case(name) {
- cx.struct_span_lint(NON_CAMEL_CASE_TYPES, ident.span, |lint| {
- let mut err = lint.build(fluent::lint::non_camel_case_type);
- let cc = to_camel_case(name);
- // We cannot provide meaningful suggestions
- // if the characters are in the category of "Lowercase Letter".
- if *name != cc {
- err.span_suggestion(
- ident.span,
- fluent::lint::suggestion,
- to_camel_case(name),
- Applicability::MaybeIncorrect,
- );
- } else {
- err.span_label(ident.span, fluent::lint::label);
- }
+ cx.struct_span_lint(
+ NON_CAMEL_CASE_TYPES,
+ ident.span,
+ fluent::lint_non_camel_case_type,
+ |lint| {
+ let cc = to_camel_case(name);
+ // We cannot provide meaningful suggestions
+ // if the characters are in the category of "Lowercase Letter".
+ if *name != cc {
+ lint.span_suggestion(
+ ident.span,
+ fluent::suggestion,
+ to_camel_case(name),
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ lint.span_label(ident.span, fluent::label);
+ }
- err.set_arg("sort", sort);
- err.set_arg("name", name);
- err.emit();
- })
+ lint.set_arg("sort", sort);
+ lint.set_arg("name", name);
+ lint
+ },
+ )
}
}
}
@@ -183,7 +187,7 @@ impl EarlyLintPass for NonCamelCaseTypes {
}
fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
- if let ast::AssocItemKind::TyAlias(..) = it.kind {
+ if let ast::AssocItemKind::Type(..) = it.kind {
self.check_case(cx, "associated type", &it.ident);
}
}
@@ -280,9 +284,8 @@ impl NonSnakeCase {
let name = ident.name.as_str();
if !is_snake_case(name) {
- cx.struct_span_lint(NON_SNAKE_CASE, ident.span, |lint| {
+ cx.struct_span_lint(NON_SNAKE_CASE, ident.span, fluent::lint_non_snake_case, |lint| {
let sc = NonSnakeCase::to_snake_case(name);
- let mut err = lint.build(fluent::lint::non_snake_case);
// We cannot provide meaningful suggestions
// if the characters are in the category of "Uppercase Letter".
if name != sc {
@@ -295,32 +298,32 @@ impl NonSnakeCase {
// Instead, recommend renaming the identifier entirely or, if permitted,
// escaping it to create a raw identifier.
if sc_ident.name.can_be_raw() {
- (fluent::lint::rename_or_convert_suggestion, sc_ident.to_string())
+ (fluent::rename_or_convert_suggestion, sc_ident.to_string())
} else {
- err.note(fluent::lint::cannot_convert_note);
- (fluent::lint::rename_suggestion, String::new())
+ lint.note(fluent::cannot_convert_note);
+ (fluent::rename_suggestion, String::new())
}
} else {
- (fluent::lint::convert_suggestion, sc.clone())
+ (fluent::convert_suggestion, sc.clone())
};
- err.span_suggestion(
+ lint.span_suggestion(
ident.span,
message,
suggestion,
Applicability::MaybeIncorrect,
);
} else {
- err.help(fluent::lint::help);
+ lint.help(fluent::help);
}
} else {
- err.span_label(ident.span, fluent::lint::label);
+ lint.span_label(ident.span, fluent::label);
}
- err.set_arg("sort", sort);
- err.set_arg("name", name);
- err.set_arg("sc", sc);
- err.emit();
+ lint.set_arg("sort", sort);
+ lint.set_arg("name", name);
+ lint.set_arg("sc", sc);
+ lint
});
}
}
@@ -478,26 +481,30 @@ impl NonUpperCaseGlobals {
fn check_upper_case(cx: &LateContext<'_>, sort: &str, ident: &Ident) {
let name = ident.name.as_str();
if name.chars().any(|c| c.is_lowercase()) {
- cx.struct_span_lint(NON_UPPER_CASE_GLOBALS, ident.span, |lint| {
- let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
- let mut err = lint.build(fluent::lint::non_upper_case_global);
- // We cannot provide meaningful suggestions
- // if the characters are in the category of "Lowercase Letter".
- if *name != uc {
- err.span_suggestion(
- ident.span,
- fluent::lint::suggestion,
- uc,
- Applicability::MaybeIncorrect,
- );
- } else {
- err.span_label(ident.span, fluent::lint::label);
- }
+ cx.struct_span_lint(
+ NON_UPPER_CASE_GLOBALS,
+ ident.span,
+ fluent::lint_non_upper_case_global,
+ |lint| {
+ let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
+ // We cannot provide meaningful suggestions
+ // if the characters are in the category of "Lowercase Letter".
+ if *name != uc {
+ lint.span_suggestion(
+ ident.span,
+ fluent::suggestion,
+ uc,
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ lint.span_label(ident.span, fluent::label);
+ }
- err.set_arg("sort", sort);
- err.set_arg("name", name);
- err.emit();
- })
+ lint.set_arg("sort", sort);
+ lint.set_arg("name", name);
+ lint
+ },
+ )
}
}
}
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index d1449496d..2ef425a10 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -1,5 +1,4 @@
use crate::context::LintContext;
-use crate::rustc_middle::ty::TypeVisitable;
use crate::LateContext;
use crate::LateLintPass;
use rustc_errors::fluent;
@@ -46,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
};
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
// traits and ignore any other method call.
- let (trait_id, did) = match cx.typeck_results().type_dependent_def(expr.hir_id) {
+ 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.
@@ -56,21 +55,17 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
Some(sym::Borrow | sym::Clone | sym::Deref)
) =>
{
- (trait_id, did)
+ did
}
_ => return,
},
_ => return,
};
- let substs = cx.typeck_results().node_substs(expr.hir_id);
- if substs.needs_subst() {
- // We can't resolve on types that require monomorphization, so we don't handle them if
- // we need to perform substitution.
- return;
- }
- let param_env = cx.tcx.param_env(trait_id);
+ let substs = cx
+ .tcx
+ .normalize_erasing_regions(cx.param_env, cx.typeck_results().node_substs(expr.hir_id));
// Resolve the trait method instance.
- let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) else {
+ let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, cx.param_env, did, substs) else {
return
};
// (Re)check that it implements the noop diagnostic.
@@ -90,13 +85,11 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
}
let expr_span = expr.span;
let span = expr_span.with_lo(receiver.span.hi());
- cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
- lint.build(fluent::lint::noop_method_call)
- .set_arg("method", call.ident.name)
+ cx.struct_span_lint(NOOP_METHOD_CALL, span, fluent::lint_noop_method_call, |lint| {
+ lint.set_arg("method", call.ident.name)
.set_arg("receiver_ty", receiver_ty)
- .span_label(span, fluent::lint::label)
- .note(fluent::lint::note)
- .emit();
+ .span_label(span, fluent::label)
+ .note(fluent::note)
});
}
}
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
new file mode 100644
index 000000000..00bf287ba
--- /dev/null
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -0,0 +1,163 @@
+use rustc_hir as hir;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_macros::{LintDiagnostic, Subdiagnostic};
+use rustc_middle::ty::{
+ self, fold::BottomUpFolder, print::TraitPredPrintModifiersAndPath, Ty, TypeFoldable,
+};
+use rustc_span::Span;
+use rustc_trait_selection::traits;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+ /// The `opaque_hidden_inferred_bound` lint detects cases in which nested
+ /// `impl Trait` in associated type bounds are not written generally enough
+ /// to satisfy the bounds of the associated type.
+ ///
+ /// ### Explanation
+ ///
+ /// This functionality was removed in #97346, but then rolled back in #99860
+ /// because it caused regressions.
+ ///
+ /// We plan on reintroducing this as a hard error, but in the mean time,
+ /// this lint serves to warn and suggest fixes for any use-cases which rely
+ /// on this behavior.
+ ///
+ /// ### Example
+ ///
+ /// ```
+ /// trait Trait {
+ /// type Assoc: Send;
+ /// }
+ ///
+ /// struct Struct;
+ ///
+ /// impl Trait for Struct {
+ /// type Assoc = i32;
+ /// }
+ ///
+ /// fn test() -> impl Trait<Assoc = impl Sized> {
+ /// Struct
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// In this example, `test` declares that the associated type `Assoc` for
+ /// `impl Trait` is `impl Sized`, which does not satisfy the `Send` bound
+ /// on the associated type.
+ ///
+ /// Although the hidden type, `i32` does satisfy this bound, we do not
+ /// consider the return type to be well-formed with this lint. It can be
+ /// fixed by changing `impl Sized` into `impl Sized + Send`.
+ pub OPAQUE_HIDDEN_INFERRED_BOUND,
+ Warn,
+ "detects the use of nested `impl Trait` types in associated type bounds that are not general enough"
+}
+
+declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]);
+
+impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
+ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
+ let hir::ItemKind::OpaqueTy(_) = &item.kind else { return; };
+ let def_id = item.owner_id.def_id.to_def_id();
+ let infcx = &cx.tcx.infer_ctxt().build();
+ // 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) {
+ // 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());
+ let ty::PredicateKind::Projection(proj) = predicate else {
+ continue;
+ };
+ // Only check types, since those are the only things that may
+ // have opaques in them anyways.
+ let Some(proj_term) = proj.term.ty() else { continue };
+
+ let proj_ty =
+ cx.tcx.mk_projection(proj.projection_ty.item_def_id, proj.projection_ty.substs);
+ // For every instance of the projection type in the bounds,
+ // replace them with the term we're assigning to the associated
+ // type in our opaque type.
+ let proj_replacer = &mut BottomUpFolder {
+ tcx: cx.tcx,
+ ty_op: |ty| if ty == proj_ty { proj_term } else { ty },
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ };
+ // For example, in `impl Trait<Assoc = impl Send>`, for all of the bounds on `Assoc`,
+ // e.g. `type Assoc: OtherTrait`, replace `<impl Trait as Trait>::Assoc: OtherTrait`
+ // with `impl Send: OtherTrait`.
+ for (assoc_pred, assoc_pred_span) in cx
+ .tcx
+ .bound_explicit_item_bounds(proj.projection_ty.item_def_id)
+ .subst_iter_copied(cx.tcx, &proj.projection_ty.substs)
+ {
+ let assoc_pred = assoc_pred.fold_with(proj_replacer);
+ let Ok(assoc_pred) = traits::fully_normalize(infcx, traits::ObligationCause::dummy(), cx.param_env, assoc_pred) else {
+ continue;
+ };
+ // If that predicate doesn't hold modulo regions (but passed during type-check),
+ // then we must've taken advantage of the hack in `project_and_unify_types` where
+ // we replace opaques with inference vars. Emit a warning!
+ if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new(
+ traits::ObligationCause::dummy(),
+ cx.param_env,
+ assoc_pred,
+ )) {
+ // If it's a trait bound and an opaque that doesn't satisfy it,
+ // then we can emit a suggestion to add the bound.
+ let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) {
+ (ty::Opaque(def_id, _), ty::PredicateKind::Trait(trait_pred)) => {
+ Some(AddBound {
+ suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(),
+ trait_ref: trait_pred.print_modifiers_and_trait_path(),
+ })
+ }
+ _ => None,
+ };
+ cx.emit_spanned_lint(
+ OPAQUE_HIDDEN_INFERRED_BOUND,
+ pred_span,
+ OpaqueHiddenInferredBoundLint {
+ ty: cx.tcx.mk_opaque(
+ def_id,
+ ty::InternalSubsts::identity_for_item(cx.tcx, def_id),
+ ),
+ proj_ty: proj_term,
+ assoc_pred_span,
+ add_bound,
+ },
+ );
+ }
+ }
+ }
+ }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_opaque_hidden_inferred_bound)]
+struct OpaqueHiddenInferredBoundLint<'tcx> {
+ ty: Ty<'tcx>,
+ proj_ty: Ty<'tcx>,
+ #[label(specifically)]
+ assoc_pred_span: Span,
+ #[subdiagnostic]
+ add_bound: Option<AddBound<'tcx>>,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion_verbose(
+ lint_opaque_hidden_inferred_bound_sugg,
+ applicability = "machine-applicable",
+ code = " + {trait_ref}"
+)]
+struct AddBound<'tcx> {
+ #[primary_span]
+ suggest_span: Span,
+ #[skip_arg]
+ trait_ref: TraitPredPrintModifiersAndPath<'tcx>,
+}
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index af5e5faf1..01bface71 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -29,18 +29,20 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue {
}
}
if let Some(t) = path_for_pass_by_value(cx, &inner_ty) {
- cx.struct_span_lint(PASS_BY_VALUE, ty.span, |lint| {
- lint.build(fluent::lint::pass_by_value)
- .set_arg("ty", t.clone())
- .span_suggestion(
+ cx.struct_span_lint(
+ PASS_BY_VALUE,
+ ty.span,
+ fluent::lint_pass_by_value,
+ |lint| {
+ lint.set_arg("ty", t.clone()).span_suggestion(
ty.span,
- fluent::lint::suggestion,
+ fluent::suggestion,
t,
// Changing type of function argument
Applicability::MaybeIncorrect,
)
- .emit();
- })
+ },
+ )
}
}
_ => {}
@@ -56,7 +58,7 @@ fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<Stri
let path_segment = path.segments.last().unwrap();
return Some(format!("{}{}", name, gen_args(cx, path_segment)));
}
- Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => {
+ Res::SelfTyAlias { alias_to: did, is_trait_impl: false, .. } => {
if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
if cx.tcx.has_attr(adt.did(), sym::rustc_pass_by_value) {
return Some(cx.tcx.def_path_str_with_substs(adt.did(), substs));
diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs
index 26f413453..3521de7fc 100644
--- a/compiler/rustc_lint/src/redundant_semicolon.rs
+++ b/compiler/rustc_lint/src/redundant_semicolon.rs
@@ -48,11 +48,18 @@ fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, boo
return;
}
- cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| {
- lint.build(fluent::lint::redundant_semicolons)
- .set_arg("multiple", multiple)
- .span_suggestion(span, fluent::lint::suggestion, "", Applicability::MaybeIncorrect)
- .emit();
- });
+ cx.struct_span_lint(
+ REDUNDANT_SEMICOLONS,
+ span,
+ fluent::lint_redundant_semicolons,
+ |lint| {
+ lint.set_arg("multiple", multiple).span_suggestion(
+ span,
+ fluent::suggestion,
+ "",
+ Applicability::MaybeIncorrect,
+ )
+ },
+ );
}
}
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index df1587c59..f22f38aa2 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -89,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
use rustc_middle::ty::PredicateKind::*;
- let predicates = cx.tcx.explicit_predicates_of(item.def_id);
+ let predicates = cx.tcx.explicit_predicates_of(item.owner_id);
for &(predicate, span) in predicates.predicates {
let Trait(trait_predicate) = predicate.kind().skip_binder() else {
continue
@@ -100,15 +100,18 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
if trait_predicate.trait_ref.self_ty().is_impl_trait() {
continue;
}
- cx.struct_span_lint(DROP_BOUNDS, span, |lint| {
- let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
- return
- };
- lint.build(fluent::lint::drop_trait_constraints)
- .set_arg("predicate", predicate)
- .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
- .emit();
- });
+ let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
+ continue;
+ };
+ cx.struct_span_lint(
+ DROP_BOUNDS,
+ span,
+ fluent::lint_drop_trait_constraints,
+ |lint| {
+ lint.set_arg("predicate", predicate)
+ .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
+ },
+ );
}
}
}
@@ -119,14 +122,11 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
};
for bound in &bounds[..] {
let def_id = bound.trait_ref.trait_def_id();
- if cx.tcx.lang_items().drop_trait() == def_id {
- cx.struct_span_lint(DYN_DROP, bound.span, |lint| {
- let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
- return
- };
- lint.build(fluent::lint::drop_glue)
- .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
- .emit();
+ if cx.tcx.lang_items().drop_trait() == def_id
+ && let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop)
+ {
+ cx.struct_span_lint(DYN_DROP, bound.span, fluent::lint_drop_glue, |lint| {
+ lint.set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
});
}
}
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 4fb6d65a6..37caab2da 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
use rustc_span::source_map;
use rustc_span::symbol::sym;
-use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_span::{Span, Symbol};
use rustc_target::abi::{Abi, WrappingRange};
use rustc_target::abi::{Integer, TagEncoding, Variants};
use rustc_target::spec::abi::Abi as SpecAbi;
@@ -116,8 +116,8 @@ impl TypeLimits {
}
}
-/// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint.
-/// Returns `true` iff the lint was overridden.
+/// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint (`expr..MAX+1`).
+/// Returns `true` iff the lint was emitted.
fn lint_overflowing_range_endpoint<'tcx>(
cx: &LateContext<'tcx>,
lit: &hir::Lit,
@@ -140,37 +140,46 @@ fn lint_overflowing_range_endpoint<'tcx>(
return false;
}
- let mut overwritten = false;
// We can suggest using an inclusive range
// (`..=`) instead only if it is the `end` that is
// overflowing and only by 1.
- if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max {
- cx.struct_span_lint(OVERFLOWING_LITERALS, struct_expr.span, |lint| {
- let mut err = lint.build(fluent::lint::range_endpoint_out_of_range);
- err.set_arg("ty", ty);
- if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) {
- use ast::{LitIntType, LitKind};
- // We need to preserve the literal's suffix,
- // as it may determine typing information.
- let suffix = match lit.node {
- LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(),
- LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(),
- LitKind::Int(_, LitIntType::Unsuffixed) => "",
- _ => bug!(),
- };
- let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
- err.span_suggestion(
- struct_expr.span,
- fluent::lint::suggestion,
- suggestion,
- Applicability::MachineApplicable,
- );
- err.emit();
- overwritten = true;
- }
- });
- }
- overwritten
+ if !(eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max) {
+ return false;
+ };
+ let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) else { return false };
+
+ cx.struct_span_lint(
+ OVERFLOWING_LITERALS,
+ struct_expr.span,
+ fluent::lint_range_endpoint_out_of_range,
+ |lint| {
+ use ast::{LitIntType, LitKind};
+
+ lint.set_arg("ty", ty);
+
+ // We need to preserve the literal's suffix,
+ // as it may determine typing information.
+ let suffix = match lit.node {
+ LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(),
+ LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(),
+ LitKind::Int(_, LitIntType::Unsuffixed) => "",
+ _ => bug!(),
+ };
+ let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
+ lint.span_suggestion(
+ struct_expr.span,
+ fluent::suggestion,
+ suggestion,
+ Applicability::MachineApplicable,
+ );
+
+ lint
+ },
+ );
+
+ // We've just emitted a lint, special cased for `(...)..MAX+1` ranges,
+ // return `true` so the callers don't also emit a lint
+ true
}
// For `isize` & `usize`, be conservative with the warnings, so that the
@@ -221,52 +230,58 @@ fn report_bin_hex_error(
negative: bool,
) {
let size = Integer::from_attr(&cx.tcx, ty).size();
- cx.struct_span_lint(OVERFLOWING_LITERALS, expr.span, |lint| {
- let (t, actually) = match ty {
- attr::IntType::SignedInt(t) => {
- let actually = if negative {
- -(size.sign_extend(val) as i128)
- } else {
- size.sign_extend(val) as i128
- };
- (t.name_str(), actually.to_string())
- }
- attr::IntType::UnsignedInt(t) => {
- let actually = size.truncate(val);
- (t.name_str(), actually.to_string())
- }
- };
- let mut err = lint.build(fluent::lint::overflowing_bin_hex);
- if negative {
- // If the value is negative,
- // emits a note about the value itself, apart from the literal.
- err.note(fluent::lint::negative_note);
- err.note(fluent::lint::negative_becomes_note);
- } else {
- err.note(fluent::lint::positive_note);
- }
- if let Some(sugg_ty) =
- get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative)
- {
- err.set_arg("suggestion_ty", sugg_ty);
- if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
- let (sans_suffix, _) = repr_str.split_at(pos);
- err.span_suggestion(
- expr.span,
- fluent::lint::suggestion,
- format!("{}{}", sans_suffix, sugg_ty),
- Applicability::MachineApplicable,
- );
+ cx.struct_span_lint(
+ OVERFLOWING_LITERALS,
+ expr.span,
+ fluent::lint_overflowing_bin_hex,
+ |lint| {
+ let (t, actually) = match ty {
+ attr::IntType::SignedInt(t) => {
+ let actually = if negative {
+ -(size.sign_extend(val) as i128)
+ } else {
+ size.sign_extend(val) as i128
+ };
+ (t.name_str(), actually.to_string())
+ }
+ attr::IntType::UnsignedInt(t) => {
+ let actually = size.truncate(val);
+ (t.name_str(), actually.to_string())
+ }
+ };
+
+ if negative {
+ // If the value is negative,
+ // emits a note about the value itself, apart from the literal.
+ lint.note(fluent::negative_note);
+ lint.note(fluent::negative_becomes_note);
} else {
- err.help(fluent::lint::help);
+ lint.note(fluent::positive_note);
}
- }
- err.set_arg("ty", t);
- err.set_arg("lit", repr_str);
- err.set_arg("dec", val);
- err.set_arg("actually", actually);
- err.emit();
- });
+ if let Some(sugg_ty) =
+ get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative)
+ {
+ lint.set_arg("suggestion_ty", sugg_ty);
+ if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
+ let (sans_suffix, _) = repr_str.split_at(pos);
+ lint.span_suggestion(
+ expr.span,
+ fluent::suggestion,
+ format!("{}{}", sans_suffix, sugg_ty),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ lint.help(fluent::help);
+ }
+ }
+ lint.set_arg("ty", t)
+ .set_arg("lit", repr_str)
+ .set_arg("dec", val)
+ .set_arg("actually", actually);
+
+ lint
+ },
+ );
}
// This function finds the next fitting type and generates a suggestion string.
@@ -345,30 +360,31 @@ fn lint_int_literal<'tcx>(
}
if lint_overflowing_range_endpoint(cx, lit, v, max, e, t.name_str()) {
- // The overflowing literal lint was overridden.
+ // The overflowing literal lint was emited by `lint_overflowing_range_endpoint`.
return;
}
- cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
- let mut err = lint.build(fluent::lint::overflowing_int);
- err.set_arg("ty", t.name_str());
- err.set_arg(
- "lit",
- cx.sess()
- .source_map()
- .span_to_snippet(lit.span)
- .expect("must get snippet from literal"),
- );
- err.set_arg("min", min);
- err.set_arg("max", max);
- err.note(fluent::lint::note);
+ cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint_overflowing_int, |lint| {
+ lint.set_arg("ty", t.name_str())
+ .set_arg(
+ "lit",
+ cx.sess()
+ .source_map()
+ .span_to_snippet(lit.span)
+ .expect("must get snippet from literal"),
+ )
+ .set_arg("min", min)
+ .set_arg("max", max)
+ .note(fluent::note);
+
if let Some(sugg_ty) =
get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
{
- err.set_arg("suggestion_ty", sugg_ty);
- err.help(fluent::lint::help);
+ lint.set_arg("suggestion_ty", sugg_ty);
+ lint.help(fluent::help);
}
- err.emit();
+
+ lint
});
}
}
@@ -393,16 +409,19 @@ fn lint_uint_literal<'tcx>(
match par_e.kind {
hir::ExprKind::Cast(..) => {
if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() {
- cx.struct_span_lint(OVERFLOWING_LITERALS, par_e.span, |lint| {
- lint.build(fluent::lint::only_cast_u8_to_char)
- .span_suggestion(
+ cx.struct_span_lint(
+ OVERFLOWING_LITERALS,
+ par_e.span,
+ fluent::lint_only_cast_u8_to_char,
+ |lint| {
+ lint.span_suggestion(
par_e.span,
- fluent::lint::suggestion,
+ fluent::suggestion,
format!("'\\u{{{:X}}}'", lit_val),
Applicability::MachineApplicable,
)
- .emit();
- });
+ },
+ );
return;
}
}
@@ -410,7 +429,7 @@ fn lint_uint_literal<'tcx>(
}
}
if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, t.name_str()) {
- // The overflowing literal lint was overridden.
+ // The overflowing literal lint was emited by `lint_overflowing_range_endpoint`.
return;
}
if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
@@ -424,9 +443,8 @@ fn lint_uint_literal<'tcx>(
);
return;
}
- cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
- lint.build(fluent::lint::overflowing_uint)
- .set_arg("ty", t.name_str())
+ cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint_overflowing_uint, |lint| {
+ lint.set_arg("ty", t.name_str())
.set_arg(
"lit",
cx.sess()
@@ -436,8 +454,7 @@ fn lint_uint_literal<'tcx>(
)
.set_arg("min", min)
.set_arg("max", max)
- .note(fluent::lint::note)
- .emit();
+ .note(fluent::note)
});
}
}
@@ -467,19 +484,22 @@ fn lint_literal<'tcx>(
_ => bug!(),
};
if is_infinite == Ok(true) {
- cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
- lint.build(fluent::lint::overflowing_literal)
- .set_arg("ty", t.name_str())
- .set_arg(
- "lit",
- cx.sess()
- .source_map()
- .span_to_snippet(lit.span)
- .expect("must get snippet from literal"),
- )
- .note(fluent::lint::note)
- .emit();
- });
+ cx.struct_span_lint(
+ OVERFLOWING_LITERALS,
+ e.span,
+ fluent::lint_overflowing_literal,
+ |lint| {
+ lint.set_arg("ty", t.name_str())
+ .set_arg(
+ "lit",
+ cx.sess()
+ .source_map()
+ .span_to_snippet(lit.span)
+ .expect("must get snippet from literal"),
+ )
+ .note(fluent::note)
+ },
+ );
}
}
_ => {}
@@ -497,9 +517,12 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
}
hir::ExprKind::Binary(binop, ref l, ref r) => {
if is_comparison(binop) && !check_limits(cx, binop, &l, &r) {
- cx.struct_span_lint(UNUSED_COMPARISONS, e.span, |lint| {
- lint.build(fluent::lint::unused_comparisons).emit();
- });
+ cx.struct_span_lint(
+ UNUSED_COMPARISONS,
+ e.span,
+ fluent::lint_unused_comparisons,
+ |lint| lint,
+ );
}
}
hir::ExprKind::Lit(ref lit) => lint_literal(cx, self, e, lit),
@@ -819,8 +842,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
self.emit_ffi_unsafe_type_lint(
ty,
sp,
- fluent::lint::improper_ctypes_array_reason,
- Some(fluent::lint::improper_ctypes_array_help),
+ fluent::lint_improper_ctypes_array_reason,
+ Some(fluent::lint_improper_ctypes_array_help),
);
true
} else {
@@ -863,7 +886,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
} else {
// All fields are ZSTs; this means that the type should behave
// like (), which is FFI-unsafe
- FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_struct_zst, help: None }
+ FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
}
} else {
// We can't completely trust repr(C) markings; make sure the fields are
@@ -877,7 +900,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
FfiPhantom(..) if def.is_enum() => {
return FfiUnsafe {
ty,
- reason: fluent::lint::improper_ctypes_enum_phantomdata,
+ reason: fluent::lint_improper_ctypes_enum_phantomdata,
help: None,
};
}
@@ -908,12 +931,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
match *ty.kind() {
ty::Adt(def, substs) => {
if def.is_box() && matches!(self.mode, CItemKind::Definition) {
- if ty.boxed_ty().is_sized(tcx.at(DUMMY_SP), self.cx.param_env) {
+ if ty.boxed_ty().is_sized(tcx, self.cx.param_env) {
return FfiSafe;
} else {
return FfiUnsafe {
ty,
- reason: fluent::lint::improper_ctypes_box,
+ reason: fluent::lint_improper_ctypes_box,
help: None,
};
}
@@ -927,14 +950,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
return FfiUnsafe {
ty,
reason: if def.is_struct() {
- fluent::lint::improper_ctypes_struct_layout_reason
+ fluent::lint_improper_ctypes_struct_layout_reason
} else {
- fluent::lint::improper_ctypes_union_layout_reason
+ fluent::lint_improper_ctypes_union_layout_reason
},
help: if def.is_struct() {
- Some(fluent::lint::improper_ctypes_struct_layout_help)
+ Some(fluent::lint_improper_ctypes_struct_layout_help)
} else {
- Some(fluent::lint::improper_ctypes_union_layout_help)
+ Some(fluent::lint_improper_ctypes_union_layout_help)
},
};
}
@@ -945,9 +968,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
return FfiUnsafe {
ty,
reason: if def.is_struct() {
- fluent::lint::improper_ctypes_struct_non_exhaustive
+ fluent::lint_improper_ctypes_struct_non_exhaustive
} else {
- fluent::lint::improper_ctypes_union_non_exhaustive
+ fluent::lint_improper_ctypes_union_non_exhaustive
},
help: None,
};
@@ -957,14 +980,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
return FfiUnsafe {
ty,
reason: if def.is_struct() {
- fluent::lint::improper_ctypes_struct_fieldless_reason
+ fluent::lint_improper_ctypes_struct_fieldless_reason
} else {
- fluent::lint::improper_ctypes_union_fieldless_reason
+ fluent::lint_improper_ctypes_union_fieldless_reason
},
help: if def.is_struct() {
- Some(fluent::lint::improper_ctypes_struct_fieldless_help)
+ Some(fluent::lint_improper_ctypes_struct_fieldless_help)
} else {
- Some(fluent::lint::improper_ctypes_union_fieldless_help)
+ Some(fluent::lint_improper_ctypes_union_fieldless_help)
},
};
}
@@ -985,8 +1008,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
if repr_nullable_ptr(self.cx, ty, self.mode).is_none() {
return FfiUnsafe {
ty,
- reason: fluent::lint::improper_ctypes_enum_repr_reason,
- help: Some(fluent::lint::improper_ctypes_enum_repr_help),
+ reason: fluent::lint_improper_ctypes_enum_repr_reason,
+ help: Some(fluent::lint_improper_ctypes_enum_repr_help),
};
}
}
@@ -994,7 +1017,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
return FfiUnsafe {
ty,
- reason: fluent::lint::improper_ctypes_non_exhaustive,
+ reason: fluent::lint_improper_ctypes_non_exhaustive,
help: None,
};
}
@@ -1005,7 +1028,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
if is_non_exhaustive && !variant.def_id.is_local() {
return FfiUnsafe {
ty,
- reason: fluent::lint::improper_ctypes_non_exhaustive_variant,
+ reason: fluent::lint_improper_ctypes_non_exhaustive_variant,
help: None,
};
}
@@ -1023,12 +1046,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
ty::Char => FfiUnsafe {
ty,
- reason: fluent::lint::improper_ctypes_char_reason,
- help: Some(fluent::lint::improper_ctypes_char_help),
+ reason: fluent::lint_improper_ctypes_char_reason,
+ help: Some(fluent::lint_improper_ctypes_char_help),
},
ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => {
- FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_128bit, help: None }
+ FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_128bit, help: None }
}
// Primitive types with a stable representation.
@@ -1036,30 +1059,30 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
ty::Slice(_) => FfiUnsafe {
ty,
- reason: fluent::lint::improper_ctypes_slice_reason,
- help: Some(fluent::lint::improper_ctypes_slice_help),
+ reason: fluent::lint_improper_ctypes_slice_reason,
+ help: Some(fluent::lint_improper_ctypes_slice_help),
},
ty::Dynamic(..) => {
- FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_dyn, help: None }
+ FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_dyn, help: None }
}
ty::Str => FfiUnsafe {
ty,
- reason: fluent::lint::improper_ctypes_str_reason,
- help: Some(fluent::lint::improper_ctypes_str_help),
+ reason: fluent::lint_improper_ctypes_str_reason,
+ help: Some(fluent::lint_improper_ctypes_str_help),
},
ty::Tuple(..) => FfiUnsafe {
ty,
- reason: fluent::lint::improper_ctypes_tuple_reason,
- help: Some(fluent::lint::improper_ctypes_tuple_help),
+ reason: fluent::lint_improper_ctypes_tuple_reason,
+ help: Some(fluent::lint_improper_ctypes_tuple_help),
},
ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _)
if {
matches!(self.mode, CItemKind::Definition)
- && ty.is_sized(self.cx.tcx.at(DUMMY_SP), self.cx.param_env)
+ && ty.is_sized(self.cx.tcx, self.cx.param_env)
} =>
{
FfiSafe
@@ -1084,8 +1107,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
if self.is_internal_abi(sig.abi()) {
return FfiUnsafe {
ty,
- reason: fluent::lint::improper_ctypes_fnptr_reason,
- help: Some(fluent::lint::improper_ctypes_fnptr_help),
+ reason: fluent::lint_improper_ctypes_fnptr_reason,
+ help: Some(fluent::lint_improper_ctypes_fnptr_help),
};
}
@@ -1116,7 +1139,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
// While opaque types are checked for earlier, if a projection in a struct field
// normalizes to an opaque type, then it will reach this branch.
ty::Opaque(..) => {
- FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_opaque, help: None }
+ FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_opaque, help: None }
}
// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
@@ -1150,25 +1173,24 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
};
- self.cx.struct_span_lint(lint, sp, |lint| {
+ self.cx.struct_span_lint(lint, sp, fluent::lint_improper_ctypes, |lint| {
let item_description = match self.mode {
CItemKind::Declaration => "block",
CItemKind::Definition => "fn",
};
- let mut diag = lint.build(fluent::lint::improper_ctypes);
- diag.set_arg("ty", ty);
- diag.set_arg("desc", item_description);
- diag.span_label(sp, fluent::lint::label);
+ lint.set_arg("ty", ty);
+ lint.set_arg("desc", item_description);
+ lint.span_label(sp, fluent::label);
if let Some(help) = help {
- diag.help(help);
+ lint.help(help);
}
- diag.note(note);
+ lint.note(note);
if let ty::Adt(def, _) = ty.kind() {
if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) {
- diag.span_note(sp, fluent::lint::note);
+ lint.span_note(sp, fluent::note);
}
}
- diag.emit();
+ lint
});
}
@@ -1202,7 +1224,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}
if let Some(ty) = ty.visit_with(&mut ProhibitOpaqueTypes { cx: self.cx }).break_value() {
- self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint::improper_ctypes_opaque, None);
+ self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint_improper_ctypes_opaque, None);
true
} else {
false
@@ -1247,7 +1269,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
self.emit_ffi_unsafe_type_lint(
ty,
sp,
- fluent::lint::improper_ctypes_only_phantomdata,
+ fluent::lint_improper_ctypes_only_phantomdata,
None,
);
}
@@ -1338,7 +1360,7 @@ declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]);
impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
if let hir::ItemKind::Enum(ref enum_definition, _) = it.kind {
- let t = cx.tcx.type_of(it.def_id);
+ let t = cx.tcx.type_of(it.owner_id);
let ty = cx.tcx.erase_regions(t);
let Ok(layout) = cx.layout_of(ty) else { return };
let Variants::Multiple {
@@ -1381,11 +1403,8 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
cx.struct_span_lint(
VARIANT_SIZE_DIFFERENCES,
enum_definition.variants[largest_index].span,
- |lint| {
- lint.build(fluent::lint::variant_size_differences)
- .set_arg("largest", largest)
- .emit();
- },
+ fluent::lint_variant_size_differences,
+ |lint| lint.set_arg("largest", largest),
);
}
}
@@ -1493,25 +1512,16 @@ impl InvalidAtomicOrdering {
fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store])
- && let Some((ordering_arg, invalid_ordering)) = match method {
- sym::load => Some((&args[0], sym::Release)),
- sym::store => Some((&args[1], sym::Acquire)),
+ && let Some((ordering_arg, invalid_ordering, msg)) = match method {
+ sym::load => Some((&args[0], sym::Release, fluent::lint_atomic_ordering_load)),
+ sym::store => Some((&args[1], sym::Acquire, fluent::lint_atomic_ordering_store)),
_ => None,
}
&& let Some(ordering) = Self::match_ordering(cx, ordering_arg)
&& (ordering == invalid_ordering || ordering == sym::AcqRel)
{
- cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, |diag| {
- if method == sym::load {
- diag.build(fluent::lint::atomic_ordering_load)
- .help(fluent::lint::help)
- .emit()
- } else {
- debug_assert_eq!(method, sym::store);
- diag.build(fluent::lint::atomic_ordering_store)
- .help(fluent::lint::help)
- .emit();
- }
+ cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, msg, |lint| {
+ lint.help(fluent::help)
});
}
}
@@ -1523,10 +1533,9 @@ impl InvalidAtomicOrdering {
&& matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence))
&& Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed)
{
- cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, |diag| {
- diag.build(fluent::lint::atomic_ordering_fence)
- .help(fluent::lint::help)
- .emit();
+ cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, fluent::lint_atomic_ordering_fence, |lint| {
+ lint
+ .help(fluent::help)
});
}
}
@@ -1545,7 +1554,7 @@ impl InvalidAtomicOrdering {
if matches!(fail_ordering, sym::Release | sym::AcqRel) {
#[derive(LintDiagnostic)]
- #[diag(lint::atomic_ordering_invalid)]
+ #[diag(lint_atomic_ordering_invalid)]
#[help]
struct InvalidAtomicOrderingDiag {
method: Symbol,
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 8c9ceb711..46706e498 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -7,6 +7,7 @@ use rustc_errors::{fluent, pluralize, Applicability, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
+use rustc_infer::traits::util::elaborate_predicates_with_span;
use rustc_middle::ty::adjustment;
use rustc_middle::ty::{self, Ty};
use rustc_span::symbol::Symbol;
@@ -154,24 +155,22 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
};
if let Some(must_use_op) = must_use_op {
- cx.struct_span_lint(UNUSED_MUST_USE, expr.span, |lint| {
- lint.build(fluent::lint::unused_op)
- .set_arg("op", must_use_op)
- .span_label(expr.span, fluent::lint::label)
+ cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint_unused_op, |lint| {
+ lint.set_arg("op", must_use_op)
+ .span_label(expr.span, fluent::label)
.span_suggestion_verbose(
expr.span.shrink_to_lo(),
- fluent::lint::suggestion,
+ fluent::suggestion,
"let _ = ",
Applicability::MachineApplicable,
)
- .emit();
});
op_warned = true;
}
if !(type_permits_lack_of_use || fn_warned || op_warned) {
- cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| {
- lint.build(fluent::lint::unused_result).set_arg("ty", ty).emit();
+ cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint_unused_result, |lint| {
+ lint.set_arg("ty", ty)
});
}
@@ -206,10 +205,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
ty::Adt(def, _) => check_must_use_def(cx, def.did(), span, descr_pre, descr_post),
ty::Opaque(def, _) => {
let mut has_emitted = false;
- for &(predicate, _) in cx.tcx.explicit_item_bounds(def) {
+ for obligation in elaborate_predicates_with_span(
+ cx.tcx,
+ cx.tcx.explicit_item_bounds(def).iter().cloned(),
+ ) {
// We only look at the `DefId`, so it is safe to skip the binder here.
if let ty::PredicateKind::Trait(ref poly_trait_predicate) =
- predicate.kind().skip_binder()
+ obligation.predicate.kind().skip_binder()
{
let def_id = poly_trait_predicate.trait_ref.def_id;
let descr_pre =
@@ -267,29 +269,35 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
}
},
ty::Closure(..) => {
- cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
- // FIXME(davidtwco): this isn't properly translatable because of the
- // pre/post strings
- lint.build(fluent::lint::unused_closure)
- .set_arg("count", plural_len)
- .set_arg("pre", descr_pre)
- .set_arg("post", descr_post)
- .note(fluent::lint::note)
- .emit();
- });
+ cx.struct_span_lint(
+ UNUSED_MUST_USE,
+ span,
+ fluent::lint_unused_closure,
+ |lint| {
+ // FIXME(davidtwco): this isn't properly translatable because of the
+ // pre/post strings
+ lint.set_arg("count", plural_len)
+ .set_arg("pre", descr_pre)
+ .set_arg("post", descr_post)
+ .note(fluent::note)
+ },
+ );
true
}
ty::Generator(..) => {
- cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
- // FIXME(davidtwco): this isn't properly translatable because of the
- // pre/post strings
- lint.build(fluent::lint::unused_generator)
- .set_arg("count", plural_len)
- .set_arg("pre", descr_pre)
- .set_arg("post", descr_post)
- .note(fluent::lint::note)
- .emit();
- });
+ cx.struct_span_lint(
+ UNUSED_MUST_USE,
+ span,
+ fluent::lint_unused_generator,
+ |lint| {
+ // FIXME(davidtwco): this isn't properly translatable because of the
+ // pre/post strings
+ lint.set_arg("count", plural_len)
+ .set_arg("pre", descr_pre)
+ .set_arg("post", descr_post)
+ .note(fluent::note)
+ },
+ );
true
}
_ => false,
@@ -309,18 +317,17 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
descr_post_path: &str,
) -> bool {
if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
- cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
+ cx.struct_span_lint(UNUSED_MUST_USE, span, fluent::lint_unused_def, |lint| {
// FIXME(davidtwco): this isn't properly translatable because of the pre/post
// strings
- let mut err = lint.build(fluent::lint::unused_def);
- err.set_arg("pre", descr_pre_path);
- err.set_arg("post", descr_post_path);
- err.set_arg("def", cx.tcx.def_path_str(def_id));
+ lint.set_arg("pre", descr_pre_path);
+ lint.set_arg("post", descr_post_path);
+ lint.set_arg("def", cx.tcx.def_path_str(def_id));
// check for #[must_use = "..."]
if let Some(note) = attr.value_str() {
- err.note(note.as_str());
+ lint.note(note.as_str());
}
- err.emit();
+ lint
});
true
} else {
@@ -357,25 +364,34 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements {
fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
if let hir::StmtKind::Semi(expr) = s.kind {
if let hir::ExprKind::Path(_) = expr.kind {
- cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| {
- let ty = cx.typeck_results().expr_ty(expr);
- if ty.needs_drop(cx.tcx, cx.param_env) {
- let mut lint = lint.build(fluent::lint::path_statement_drop);
- if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
- lint.span_suggestion(
- s.span,
- fluent::lint::suggestion,
- format!("drop({});", snippet),
- Applicability::MachineApplicable,
- );
- } else {
- lint.span_help(s.span, fluent::lint::suggestion);
- }
- lint.emit();
- } else {
- lint.build(fluent::lint::path_statement_no_effect).emit();
- }
- });
+ let ty = cx.typeck_results().expr_ty(expr);
+ if ty.needs_drop(cx.tcx, cx.param_env) {
+ cx.struct_span_lint(
+ PATH_STATEMENTS,
+ s.span,
+ fluent::lint_path_statement_drop,
+ |lint| {
+ if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
+ lint.span_suggestion(
+ s.span,
+ fluent::suggestion,
+ format!("drop({});", snippet),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ lint.span_help(s.span, fluent::suggestion);
+ }
+ lint
+ },
+ );
+ } else {
+ cx.struct_span_lint(
+ PATH_STATEMENTS,
+ s.span,
+ fluent::lint_path_statement_no_effect,
+ |lint| lint,
+ );
+ }
}
}
}
@@ -545,22 +561,21 @@ trait UnusedDelimLint {
} else {
MultiSpan::from(value_span)
};
- cx.struct_span_lint(self.lint(), primary_span, |lint| {
- let mut db = lint.build(fluent::lint::unused_delim);
- db.set_arg("delim", Self::DELIM_STR);
- db.set_arg("item", msg);
+ cx.struct_span_lint(self.lint(), primary_span, fluent::lint_unused_delim, |lint| {
+ lint.set_arg("delim", Self::DELIM_STR);
+ lint.set_arg("item", msg);
if let Some((lo, hi)) = spans {
let replacement = vec![
(lo, if keep_space.0 { " ".into() } else { "".into() }),
(hi, if keep_space.1 { " ".into() } else { "".into() }),
];
- db.multipart_suggestion(
- fluent::lint::suggestion,
+ lint.multipart_suggestion(
+ fluent::suggestion,
replacement,
Applicability::MachineApplicable,
);
}
- db.emit();
+ lint
});
}
@@ -608,8 +623,7 @@ trait UnusedDelimLint {
ref call_or_other => {
let (args_to_check, ctx) = match *call_or_other {
Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg),
- // first "argument" is self (which sometimes needs delims)
- MethodCall(_, ref args, _) => (&args[1..], UnusedDelimsCtx::MethodArg),
+ MethodCall(_, _, ref args, _) => (&args[..], UnusedDelimsCtx::MethodArg),
// actual catch-all arm
_ => {
return;
@@ -1129,9 +1143,12 @@ impl UnusedImportBraces {
ast::UseTreeKind::Nested(_) => return,
};
- cx.struct_span_lint(UNUSED_IMPORT_BRACES, item.span, |lint| {
- lint.build(fluent::lint::unused_import_braces).set_arg("node", node_name).emit();
- });
+ cx.struct_span_lint(
+ UNUSED_IMPORT_BRACES,
+ item.span,
+ fluent::lint_unused_import_braces,
+ |lint| lint.set_arg("node", node_name),
+ );
}
}
}
@@ -1180,15 +1197,17 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation {
for adj in cx.typeck_results().expr_adjustments(e) {
if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
- cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| {
- lint.build(match m {
- adjustment::AutoBorrowMutability::Not => fluent::lint::unused_allocation,
+ cx.struct_span_lint(
+ UNUSED_ALLOCATION,
+ e.span,
+ match m {
+ adjustment::AutoBorrowMutability::Not => fluent::lint_unused_allocation,
adjustment::AutoBorrowMutability::Mut { .. } => {
- fluent::lint::unused_allocation_mut
+ fluent::lint_unused_allocation_mut
}
- })
- .emit();
- });
+ },
+ |lint| lint,
+ );
}
}
}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index e5dfda24d..61ee467f5 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -264,37 +264,6 @@ declare_lint! {
}
declare_lint! {
- /// The `const_err` lint detects an erroneous expression while doing
- /// constant evaluation.
- ///
- /// ### Example
- ///
- /// ```rust,compile_fail
- /// #![allow(unconditional_panic)]
- /// const C: i32 = 1/0;
- /// ```
- ///
- /// {{produces}}
- ///
- /// ### Explanation
- ///
- /// This lint detects constants that fail to evaluate. Allowing the lint will accept the
- /// constant declaration, but any use of this constant will still lead to a hard error. This is
- /// a future incompatibility lint; the plan is to eventually entirely forbid even declaring
- /// constants that cannot be evaluated. See [issue #71800] for more details.
- ///
- /// [issue #71800]: https://github.com/rust-lang/rust/issues/71800
- pub CONST_ERR,
- Deny,
- "constant evaluation encountered erroneous expression",
- @future_incompatible = FutureIncompatibleInfo {
- reference: "issue #71800 <https://github.com/rust-lang/rust/issues/71800>",
- reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
- };
- report_in_external_macro
-}
-
-declare_lint! {
/// The `unused_imports` lint detects imports that are never used.
///
/// ### Example
@@ -1458,6 +1427,7 @@ declare_lint! {
"trait-object types were treated as different depending on marker-trait order",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #56484 <https://github.com/rust-lang/rust/issues/56484>",
+ reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
};
}
@@ -2909,7 +2879,7 @@ declare_lint! {
/// ### Example
///
/// ```rust
- /// #![feature(naked_functions)]
+ /// #![feature(asm_experimental_arch, naked_functions)]
///
/// use std::arch::asm;
///
@@ -3295,7 +3265,6 @@ declare_lint_pass! {
EXPORTED_PRIVATE_DEPENDENCIES,
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
INVALID_TYPE_PARAM_DEFAULT,
- CONST_ERR,
RENAMED_AND_REMOVED_LINTS,
UNALIGNED_REFERENCES,
CONST_ITEM_MUTATION,
@@ -3969,7 +3938,7 @@ declare_lint! {
///
/// The compiler disables the automatic implementation if an explicit one
/// exists for given type constructor. The exact rules governing this
- /// are currently unsound and quite subtle and and will be modified in the future.
+ /// are currently unsound, quite subtle, and will be modified in the future.
/// This change will cause the automatic implementation to be disabled in more
/// cases, potentially breaking some code.
pub SUSPICIOUS_AUTO_TRAIT_IMPLS,
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 11b2d057a..aa54b3d8a 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -25,6 +25,9 @@ macro_rules! pluralize {
($x:expr) => {
if $x != 1 { "s" } else { "" }
};
+ ("has", $x:expr) => {
+ if $x == 1 { "has" } else { "have" }
+ };
("is", $x:expr) => {
if $x == 1 { "is" } else { "are" }
};
@@ -92,7 +95,7 @@ pub enum LintExpectationId {
/// stable and can be cached. The additional index ensures that nodes with
/// several expectations can correctly match diagnostics to the individual
/// expectation.
- Stable { hir_id: HirId, attr_index: u16, lint_index: Option<u16> },
+ Stable { hir_id: HirId, attr_index: u16, lint_index: Option<u16>, attr_id: Option<AttrId> },
}
impl LintExpectationId {
@@ -116,13 +119,31 @@ impl LintExpectationId {
*lint_index = new_lint_index
}
+
+ /// Prepares the id for hashing. Removes references to the ast.
+ /// Should only be called when the id is stable.
+ pub fn normalize(self) -> Self {
+ match self {
+ Self::Stable { hir_id, attr_index, lint_index, .. } => {
+ Self::Stable { hir_id, attr_index, lint_index, attr_id: None }
+ }
+ Self::Unstable { .. } => {
+ unreachable!("`normalize` called when `ExpectationId` is unstable")
+ }
+ }
+ }
}
impl<HCX: rustc_hir::HashStableContext> HashStable<HCX> for LintExpectationId {
#[inline]
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
match self {
- LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
+ LintExpectationId::Stable {
+ hir_id,
+ attr_index,
+ lint_index: Some(lint_index),
+ attr_id: _,
+ } => {
hir_id.hash_stable(hcx, hasher);
attr_index.hash_stable(hcx, hasher);
lint_index.hash_stable(hcx, hasher);
@@ -142,9 +163,12 @@ impl<HCX: rustc_hir::HashStableContext> ToStableHashKey<HCX> for LintExpectation
#[inline]
fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
match self {
- LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
- (*hir_id, *attr_index, *lint_index)
- }
+ LintExpectationId::Stable {
+ hir_id,
+ attr_index,
+ lint_index: Some(lint_index),
+ attr_id: _,
+ } => (*hir_id, *attr_index, *lint_index),
_ => {
unreachable!("HashStable should only be called for a filled `LintExpectationId`")
}
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 24e188260..18d37d95a 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -31,13 +31,12 @@
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "llvm/Transforms/IPO/FunctionImport.h"
-#if LLVM_VERSION_GE(15, 0)
+#include "llvm/Transforms/IPO/Internalize.h"
#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
-#endif
#include "llvm/Transforms/Utils/AddDiscriminators.h"
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
#include "llvm/LTO/LTO.h"
-#include "llvm/Bitcode/BitcodeWriterPass.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm-c/Transforms/PassManagerBuilder.h"
#include "llvm/Transforms/Instrumentation.h"
@@ -70,7 +69,9 @@ extern "C" void LLVMInitializePasses() {
initializeAnalysis(Registry);
initializeTransformUtils(Registry);
initializeInstCombine(Registry);
+#if LLVM_VERSION_LT(16, 0)
initializeInstrumentation(Registry);
+#endif
initializeTarget(Registry);
}
@@ -93,172 +94,6 @@ extern "C" void LLVMTimeTraceProfilerFinish(const char* FileName) {
timeTraceProfilerCleanup();
}
-extern "C" LLVMPassRef LLVMRustFindAndCreatePass(const char *PassName) {
-#if LLVM_VERSION_LT(15, 0)
- StringRef SR(PassName);
- PassRegistry *PR = PassRegistry::getPassRegistry();
-
- const PassInfo *PI = PR->getPassInfo(SR);
- if (PI) {
- return wrap(PI->createPass());
- }
- return nullptr;
-#else
- report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" LLVMPassRef LLVMRustCreateAddressSanitizerFunctionPass(bool Recover) {
-#if LLVM_VERSION_LT(15, 0)
- const bool CompileKernel = false;
- const bool UseAfterScope = true;
-
- return wrap(createAddressSanitizerFunctionPass(CompileKernel, Recover, UseAfterScope));
-#else
- report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" LLVMPassRef LLVMRustCreateModuleAddressSanitizerPass(bool Recover) {
-#if LLVM_VERSION_LT(15, 0)
- const bool CompileKernel = false;
-
- return wrap(createModuleAddressSanitizerLegacyPassPass(CompileKernel, Recover));
-#else
- report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" LLVMPassRef LLVMRustCreateMemorySanitizerPass(int TrackOrigins, bool Recover) {
-#if LLVM_VERSION_LT(15, 0)
- const bool CompileKernel = false;
-
- return wrap(createMemorySanitizerLegacyPassPass(
-#if LLVM_VERSION_GE(14, 0)
- MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel, /*EagerChecks=*/true}
-#else
- MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel}
-#endif
- ));
-#else
- report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" LLVMPassRef LLVMRustCreateThreadSanitizerPass() {
-#if LLVM_VERSION_LT(15, 0)
- return wrap(createThreadSanitizerLegacyPassPass());
-#else
- report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" LLVMPassRef LLVMRustCreateHWAddressSanitizerPass(bool Recover) {
-#if LLVM_VERSION_LT(15, 0)
- const bool CompileKernel = false;
-
- return wrap(createHWAddressSanitizerLegacyPassPass(CompileKernel, Recover));
-#else
- report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" void LLVMRustAddPass(LLVMPassManagerRef PMR, LLVMPassRef RustPass) {
-#if LLVM_VERSION_LT(15, 0)
- assert(RustPass);
- Pass *Pass = unwrap(RustPass);
- PassManagerBase *PMB = unwrap(PMR);
- PMB->add(Pass);
-#else
- report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" LLVMPassManagerBuilderRef LLVMRustPassManagerBuilderCreate() {
-#if LLVM_VERSION_LT(15, 0)
- return LLVMPassManagerBuilderCreate();
-#else
- report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" void LLVMRustPassManagerBuilderDispose(LLVMPassManagerBuilderRef PMB) {
-#if LLVM_VERSION_LT(15, 0)
- LLVMPassManagerBuilderDispose(PMB);
-#else
- report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" void LLVMRustPassManagerBuilderPopulateFunctionPassManager(
- LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM) {
-#if LLVM_VERSION_LT(15, 0)
- LLVMPassManagerBuilderPopulateFunctionPassManager(PMB, PM);
-#else
- report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" void LLVMRustPassManagerBuilderPopulateModulePassManager(
- LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM) {
-#if LLVM_VERSION_LT(15, 0)
- LLVMPassManagerBuilderPopulateModulePassManager(PMB, PM);
-#else
- report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" void LLVMRustPassManagerBuilderPopulateLTOPassManager(
- LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM, bool Internalize, bool RunInliner) {
-#if LLVM_VERSION_LT(15, 0)
- LLVMPassManagerBuilderPopulateLTOPassManager(PMB, PM, Internalize, RunInliner);
-#else
- report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C"
-void LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
- LLVMPassManagerBuilderRef PMBR,
- LLVMPassManagerRef PMR
-) {
-#if LLVM_VERSION_LT(15, 0)
- unwrap(PMBR)->populateThinLTOPassManager(*unwrap(PMR));
-#else
- report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C" void LLVMRustPassManagerBuilderUseInlinerWithThreshold(
- LLVMPassManagerBuilderRef PMB, unsigned Threshold) {
-#if LLVM_VERSION_LT(15, 0)
- LLVMPassManagerBuilderUseInlinerWithThreshold(PMB, Threshold);
-#else
- report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-extern "C"
-void LLVMRustAddLastExtensionPasses(
- LLVMPassManagerBuilderRef PMBR, LLVMPassRef *Passes, size_t NumPasses) {
-#if LLVM_VERSION_LT(15, 0)
- auto AddExtensionPasses = [Passes, NumPasses](
- const PassManagerBuilder &Builder, PassManagerBase &PM) {
- for (size_t I = 0; I < NumPasses; I++) {
- PM.add(unwrap(Passes[I]));
- }
- };
- // Add the passes to both of the pre-finalization extension points,
- // so they are run for optimized and non-optimized builds.
- unwrap(PMBR)->addExtension(PassManagerBuilder::EP_OptimizerLast,
- AddExtensionPasses);
- unwrap(PMBR)->addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
- AddExtensionPasses);
-#else
- report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
#ifdef LLVM_COMPONENT_X86
#define SUBTARGET_X86 SUBTARGET(X86)
#else
@@ -604,47 +439,6 @@ extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
delete unwrap(TM);
}
-extern "C" void LLVMRustConfigurePassManagerBuilder(
- LLVMPassManagerBuilderRef PMBR, LLVMRustCodeGenOptLevel OptLevel,
- bool MergeFunctions, bool SLPVectorize, bool LoopVectorize, bool PrepareForThinLTO,
- const char* PGOGenPath, const char* PGOUsePath, const char* PGOSampleUsePath,
- int SizeLevel) {
-#if LLVM_VERSION_LT(15, 0)
- unwrap(PMBR)->MergeFunctions = MergeFunctions;
- unwrap(PMBR)->SLPVectorize = SLPVectorize;
- unwrap(PMBR)->OptLevel = fromRust(OptLevel);
- unwrap(PMBR)->LoopVectorize = LoopVectorize;
- unwrap(PMBR)->PrepareForThinLTO = PrepareForThinLTO;
- unwrap(PMBR)->SizeLevel = SizeLevel;
- unwrap(PMBR)->DisableUnrollLoops = SizeLevel != 0;
-
- if (PGOGenPath) {
- assert(!PGOUsePath && !PGOSampleUsePath);
- unwrap(PMBR)->EnablePGOInstrGen = true;
- unwrap(PMBR)->PGOInstrGen = PGOGenPath;
- } else if (PGOUsePath) {
- assert(!PGOSampleUsePath);
- unwrap(PMBR)->PGOInstrUse = PGOUsePath;
- } else if (PGOSampleUsePath) {
- unwrap(PMBR)->PGOSampleUse = PGOSampleUsePath;
- }
-#else
- report_fatal_error("Legacy PM not supported with LLVM 15");
-#endif
-}
-
-// Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo`
-// field of a PassManagerBuilder, we expose our own method of doing so.
-extern "C" void LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMBR,
- LLVMModuleRef M,
- bool DisableSimplifyLibCalls) {
- Triple TargetTriple(unwrap(M)->getTargetTriple());
- TargetLibraryInfoImpl *TLI = new TargetLibraryInfoImpl(TargetTriple);
- if (DisableSimplifyLibCalls)
- TLI->disableAllFunctions();
- unwrap(PMBR)->LibraryInfo = TLI;
-}
-
// Unfortunately, the LLVM C API doesn't provide a way to create the
// TargetLibraryInfo pass, so we use this method to do so.
extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M,
@@ -656,27 +450,6 @@ extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M,
unwrap(PMR)->add(new TargetLibraryInfoWrapperPass(TLII));
}
-// Unfortunately, the LLVM C API doesn't provide an easy way of iterating over
-// all the functions in a module, so we do that manually here. You'll find
-// similar code in clang's BackendUtil.cpp file.
-extern "C" void LLVMRustRunFunctionPassManager(LLVMPassManagerRef PMR,
- LLVMModuleRef M) {
- llvm::legacy::FunctionPassManager *P =
- unwrap<llvm::legacy::FunctionPassManager>(PMR);
- P->doInitialization();
-
- // Upgrade all calls to old intrinsics first.
- for (Module::iterator I = unwrap(M)->begin(), E = unwrap(M)->end(); I != E;)
- UpgradeCallsToIntrinsic(&*I++); // must be post-increment, as we remove
-
- for (Module::iterator I = unwrap(M)->begin(), E = unwrap(M)->end(); I != E;
- ++I)
- if (!I->isDeclaration())
- P->run(*I);
-
- P->doFinalization();
-}
-
extern "C" void LLVMRustSetLLVMOptions(int Argc, char **Argv) {
// Initializing the command-line options more than once is not allowed. So,
// check if they've already been initialized. (This could happen if we're
@@ -820,7 +593,7 @@ struct LLVMRustSanitizerOptions {
};
extern "C" LLVMRustResult
-LLVMRustOptimizeWithNewPassManager(
+LLVMRustOptimize(
LLVMModuleRef ModuleRef,
LLVMTargetMachineRef TMRef,
LLVMRustPassBuilderOptLevel OptLevelRust,
@@ -1241,15 +1014,8 @@ extern "C" void LLVMRustPrintPasses() {
PR->enumerateWith(&Listener);
}
-extern "C" void LLVMRustAddAlwaysInlinePass(LLVMPassManagerBuilderRef PMBR,
- bool AddLifetimes) {
- unwrap(PMBR)->Inliner = llvm::createAlwaysInlinerLegacyPass(AddLifetimes);
-}
-
extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols,
size_t Len) {
- llvm::legacy::PassManager passes;
-
auto PreserveFunctions = [=](const GlobalValue &GV) {
for (size_t I = 0; I < Len; I++) {
if (GV.getName() == Symbols[I]) {
@@ -1259,9 +1025,7 @@ extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols,
return false;
};
- passes.add(llvm::createInternalizePass(PreserveFunctions));
-
- passes.run(*unwrap(M));
+ internalizeModule(*unwrap(M), PreserveFunctions);
}
extern "C" void
@@ -1282,7 +1046,7 @@ extern "C" void LLVMRustSetModulePIELevel(LLVMModuleRef M) {
extern "C" void LLVMRustSetModuleCodeModel(LLVMModuleRef M,
LLVMRustCodeModel Model) {
auto CM = fromRust(Model);
- if (!CM.hasValue())
+ if (!CM)
return;
unwrap(M)->setCodeModel(*CM);
}
@@ -1610,11 +1374,6 @@ LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) {
raw_string_ostream OS(Ret->data);
{
if (is_thin) {
-#if LLVM_VERSION_LT(15, 0)
- legacy::PassManager PM;
- PM.add(createWriteThinLTOBitcodePass(OS));
- PM.run(*unwrap(M));
-#else
PassBuilder PB;
LoopAnalysisManager LAM;
FunctionAnalysisManager FAM;
@@ -1628,11 +1387,8 @@ LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin) {
ModulePassManager MPM;
MPM.addPass(ThinLTOBitcodeWriterPass(OS, nullptr));
MPM.run(*unwrap(M), MAM);
-#endif
} else {
- legacy::PassManager PM;
- PM.add(createBitcodeWriterPass(OS));
- PM.run(*unwrap(M));
+ WriteBitcodeToFile(*unwrap(M), OS);
}
}
}
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 6ee3c7d68..6f36281af 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -12,7 +12,7 @@
#include "llvm/Object/COFFImportFile.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Pass.h"
-#include "llvm/Bitcode/BitcodeWriterPass.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/Support/Signals.h"
#include "llvm/ADT/Optional.h"
@@ -406,45 +406,6 @@ extern "C" LLVMValueRef LLVMRustBuildAtomicStore(LLVMBuilderRef B,
return wrap(SI);
}
-// FIXME: Use the C-API LLVMBuildAtomicCmpXchg and LLVMSetWeak
-// once we raise our minimum support to LLVM 10.
-extern "C" LLVMValueRef
-LLVMRustBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Target,
- LLVMValueRef Old, LLVMValueRef Source,
- LLVMAtomicOrdering Order,
- LLVMAtomicOrdering FailureOrder, LLVMBool Weak) {
- // Rust probably knows the alignment of the target value and should be able to
- // specify something more precise than MaybeAlign here. See also
- // https://reviews.llvm.org/D97224 which may be a useful reference.
- AtomicCmpXchgInst *ACXI = unwrap(B)->CreateAtomicCmpXchg(
- unwrap(Target), unwrap(Old), unwrap(Source), llvm::MaybeAlign(), fromRust(Order),
- fromRust(FailureOrder));
- ACXI->setWeak(Weak);
- return wrap(ACXI);
-}
-
-enum class LLVMRustSynchronizationScope {
- SingleThread,
- CrossThread,
-};
-
-static SyncScope::ID fromRust(LLVMRustSynchronizationScope Scope) {
- switch (Scope) {
- case LLVMRustSynchronizationScope::SingleThread:
- return SyncScope::SingleThread;
- case LLVMRustSynchronizationScope::CrossThread:
- return SyncScope::System;
- default:
- report_fatal_error("bad SynchronizationScope.");
- }
-}
-
-extern "C" LLVMValueRef
-LLVMRustBuildAtomicFence(LLVMBuilderRef B, LLVMAtomicOrdering Order,
- LLVMRustSynchronizationScope Scope) {
- return wrap(unwrap(B)->CreateFence(fromRust(Order), fromRust(Scope)));
-}
-
enum class LLVMRustAsmDialect {
Att,
Intel,
@@ -1709,11 +1670,7 @@ LLVMRustModuleBufferCreate(LLVMModuleRef M) {
auto Ret = std::make_unique<LLVMRustModuleBuffer>();
{
raw_string_ostream OS(Ret->data);
- {
- legacy::PassManager PM;
- PM.add(createBitcodeWriterPass(OS));
- PM.run(*unwrap(M));
- }
+ WriteBitcodeToFile(*unwrap(M), OS);
}
return Ret.release();
}
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index cf1c59455..ef1985b96 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -2,94 +2,77 @@
use crate::diagnostics::diagnostic_builder::{DiagnosticDeriveBuilder, DiagnosticDeriveKind};
use crate::diagnostics::error::{span_err, DiagnosticDeriveError};
-use crate::diagnostics::utils::{build_field_mapping, SetOnce};
+use crate::diagnostics::utils::SetOnce;
use proc_macro2::TokenStream;
use quote::quote;
-use syn::spanned::Spanned;
use synstructure::Structure;
/// The central struct for constructing the `into_diagnostic` method from an annotated struct.
-pub(crate) struct SessionDiagnosticDerive<'a> {
+pub(crate) struct DiagnosticDerive<'a> {
structure: Structure<'a>,
- sess: syn::Ident,
builder: DiagnosticDeriveBuilder,
}
-impl<'a> SessionDiagnosticDerive<'a> {
- pub(crate) fn new(diag: syn::Ident, sess: syn::Ident, structure: Structure<'a>) -> Self {
+impl<'a> DiagnosticDerive<'a> {
+ pub(crate) fn new(diag: syn::Ident, handler: syn::Ident, structure: Structure<'a>) -> Self {
Self {
builder: DiagnosticDeriveBuilder {
diag,
- fields: build_field_mapping(&structure),
- kind: DiagnosticDeriveKind::SessionDiagnostic,
- code: None,
- slug: None,
+ kind: DiagnosticDeriveKind::Diagnostic { handler },
},
- sess,
structure,
}
}
pub(crate) fn into_tokens(self) -> TokenStream {
- let SessionDiagnosticDerive { mut structure, sess, mut builder } = self;
-
- let ast = structure.ast();
- let implementation = {
- if let syn::Data::Struct(..) = ast.data {
- let preamble = builder.preamble(&structure);
- let (attrs, args) = builder.body(&mut structure);
-
- let span = ast.span().unwrap();
- let diag = &builder.diag;
- let init = match builder.slug.value() {
- None => {
- span_err(span, "diagnostic slug not specified")
- .help(&format!(
- "specify the slug as the first argument to the `#[diag(...)]` attribute, \
- such as `#[diag(typeck::example_error)]`",
- ))
- .emit();
- return DiagnosticDeriveError::ErrorHandled.to_compile_error();
- }
- Some(slug) => {
- quote! {
- let mut #diag = #sess.struct_diagnostic(rustc_errors::fluent::#slug);
- }
- }
- };
-
- quote! {
- #init
- #preamble
- match self {
- #attrs
- }
- match self {
- #args
+ let DiagnosticDerive { mut structure, mut builder } = self;
+
+ let implementation = builder.each_variant(&mut structure, |mut builder, variant| {
+ let preamble = builder.preamble(&variant);
+ let body = builder.body(&variant);
+
+ let diag = &builder.parent.diag;
+ let DiagnosticDeriveKind::Diagnostic { handler } = &builder.parent.kind else {
+ unreachable!()
+ };
+ let init = match builder.slug.value_ref() {
+ None => {
+ span_err(builder.span, "diagnostic slug not specified")
+ .help(&format!(
+ "specify the slug as the first argument to the `#[diag(...)]` \
+ attribute, such as `#[diag(hir_analysis_example_error)]`",
+ ))
+ .emit();
+ return DiagnosticDeriveError::ErrorHandled.to_compile_error();
+ }
+ Some(slug) => {
+ quote! {
+ let mut #diag = #handler.struct_diagnostic(rustc_errors::fluent::#slug);
}
- #diag
}
- } else {
- span_err(
- ast.span().unwrap(),
- "`#[derive(SessionDiagnostic)]` can only be used on structs",
- )
- .emit();
-
- DiagnosticDeriveError::ErrorHandled.to_compile_error()
+ };
+
+ let formatting_init = &builder.formatting_init;
+ quote! {
+ #init
+ #formatting_init
+ #preamble
+ #body
+ #diag
}
- };
+ });
+ let DiagnosticDeriveKind::Diagnostic { handler } = &builder.kind else { unreachable!() };
structure.gen_impl(quote! {
- gen impl<'__session_diagnostic_sess, G>
- rustc_session::SessionDiagnostic<'__session_diagnostic_sess, G>
+ gen impl<'__diagnostic_handler_sess, G>
+ rustc_errors::IntoDiagnostic<'__diagnostic_handler_sess, G>
for @Self
where G: rustc_errors::EmissionGuarantee
{
fn into_diagnostic(
self,
- #sess: &'__session_diagnostic_sess rustc_errors::Handler
- ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, G> {
+ #handler: &'__diagnostic_handler_sess rustc_errors::Handler
+ ) -> rustc_errors::DiagnosticBuilder<'__diagnostic_handler_sess, G> {
use rustc_errors::IntoDiagnosticArg;
#implementation
}
@@ -107,13 +90,7 @@ pub(crate) struct LintDiagnosticDerive<'a> {
impl<'a> LintDiagnosticDerive<'a> {
pub(crate) fn new(diag: syn::Ident, structure: Structure<'a>) -> Self {
Self {
- builder: DiagnosticDeriveBuilder {
- diag,
- fields: build_field_mapping(&structure),
- kind: DiagnosticDeriveKind::LintDiagnostic,
- code: None,
- slug: None,
- },
+ builder: DiagnosticDeriveBuilder { diag, kind: DiagnosticDeriveKind::LintDiagnostic },
structure,
}
}
@@ -121,62 +98,52 @@ impl<'a> LintDiagnosticDerive<'a> {
pub(crate) fn into_tokens(self) -> TokenStream {
let LintDiagnosticDerive { mut structure, mut builder } = self;
- let ast = structure.ast();
- let implementation = {
- if let syn::Data::Struct(..) = ast.data {
- let preamble = builder.preamble(&structure);
- let (attrs, args) = builder.body(&mut structure);
-
- let diag = &builder.diag;
- let span = ast.span().unwrap();
- let init = match builder.slug.value() {
- None => {
- span_err(span, "diagnostic slug not specified")
- .help(&format!(
- "specify the slug as the first argument to the attribute, such as \
- `#[diag(typeck::example_error)]`",
- ))
- .emit();
- return DiagnosticDeriveError::ErrorHandled.to_compile_error();
- }
- Some(slug) => {
- quote! {
- let mut #diag = #diag.build(rustc_errors::fluent::#slug);
- }
- }
- };
-
- let implementation = quote! {
- #init
- #preamble
- match self {
- #attrs
- }
- match self {
- #args
- }
- #diag.emit();
- };
-
- implementation
- } else {
- span_err(
- ast.span().unwrap(),
- "`#[derive(LintDiagnostic)]` can only be used on structs",
- )
- .emit();
-
- DiagnosticDeriveError::ErrorHandled.to_compile_error()
+ let implementation = builder.each_variant(&mut structure, |mut builder, variant| {
+ let preamble = builder.preamble(&variant);
+ let body = builder.body(&variant);
+
+ let diag = &builder.parent.diag;
+ let formatting_init = &builder.formatting_init;
+ quote! {
+ #preamble
+ #formatting_init
+ #body
+ #diag
}
- };
+ });
+
+ let msg = builder.each_variant(&mut structure, |mut builder, variant| {
+ // Collect the slug by generating the preamble.
+ let _ = builder.preamble(&variant);
+
+ match builder.slug.value_ref() {
+ None => {
+ span_err(builder.span, "diagnostic slug not specified")
+ .help(&format!(
+ "specify the slug as the first argument to the attribute, such as \
+ `#[diag(compiletest_example)]`",
+ ))
+ .emit();
+ return DiagnosticDeriveError::ErrorHandled.to_compile_error();
+ }
+ Some(slug) => quote! { rustc_errors::fluent::#slug.into() },
+ }
+ });
let diag = &builder.diag;
structure.gen_impl(quote! {
gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self {
- fn decorate_lint(self, #diag: rustc_errors::LintDiagnosticBuilder<'__a, ()>) {
+ fn decorate_lint<'__b>(
+ self,
+ #diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()>
+ ) -> &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> {
use rustc_errors::IntoDiagnosticArg;
#implementation
}
+
+ fn msg(&self) -> rustc_errors::DiagnosticMessage {
+ #msg
+ }
}
})
}
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 2a4fe48a8..3ea83fd09 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -5,56 +5,124 @@ use crate::diagnostics::error::{
DiagnosticDeriveError,
};
use crate::diagnostics::utils::{
- report_error_if_not_applied_to_span, report_type_error, type_is_unit, type_matches_path,
- Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce,
+ build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error,
+ should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy, FieldMap,
+ HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
};
use proc_macro2::{Ident, Span, TokenStream};
use quote::{format_ident, quote};
-use std::collections::HashMap;
-use std::str::FromStr;
use syn::{
- parse_quote, spanned::Spanned, Attribute, Field, Meta, MetaList, MetaNameValue, NestedMeta,
- Path, Type,
+ parse_quote, spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path, Type,
};
-use synstructure::{BindingInfo, Structure};
+use synstructure::{BindingInfo, Structure, VariantInfo};
/// What kind of diagnostic is being derived - a fatal/error/warning or a lint?
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq)]
pub(crate) enum DiagnosticDeriveKind {
- SessionDiagnostic,
+ Diagnostic { handler: syn::Ident },
LintDiagnostic,
}
-/// Tracks persistent information required for building up individual calls to diagnostic methods
-/// for generated diagnostic derives - both `SessionDiagnostic` for fatal/errors/warnings and
-/// `LintDiagnostic` for lints.
+/// Tracks persistent information required for the entire type when building up individual calls to
+/// diagnostic methods for generated diagnostic derives - both `Diagnostic` for
+/// fatal/errors/warnings and `LintDiagnostic` for lints.
pub(crate) struct DiagnosticDeriveBuilder {
/// The identifier to use for the generated `DiagnosticBuilder` instance.
pub diag: syn::Ident,
+ /// Kind of diagnostic that should be derived.
+ pub kind: DiagnosticDeriveKind,
+}
+
+/// Tracks persistent information required for a specific variant when building up individual calls
+/// to diagnostic methods for generated diagnostic derives - both `Diagnostic` for
+/// fatal/errors/warnings and `LintDiagnostic` for lints.
+pub(crate) struct DiagnosticDeriveVariantBuilder<'parent> {
+ /// The parent builder for the entire type.
+ pub parent: &'parent DiagnosticDeriveBuilder,
+
+ /// Initialization of format strings for code suggestions.
+ pub formatting_init: TokenStream,
+
+ /// Span of the struct or the enum variant.
+ pub span: proc_macro::Span,
/// Store a map of field name to its corresponding field. This is built on construction of the
/// derive builder.
- pub fields: HashMap<String, TokenStream>,
+ pub field_map: FieldMap,
- /// Kind of diagnostic that should be derived.
- pub kind: DiagnosticDeriveKind,
/// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that
/// has the actual diagnostic message.
- pub slug: Option<(Path, proc_macro::Span)>,
+ pub slug: SpannedOption<Path>,
/// Error codes are a optional part of the struct attribute - this is only set to detect
/// multiple specifications.
- pub code: Option<(String, proc_macro::Span)>,
+ pub code: SpannedOption<()>,
}
-impl HasFieldMap for DiagnosticDeriveBuilder {
+impl<'a> HasFieldMap for DiagnosticDeriveVariantBuilder<'a> {
fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
- self.fields.get(field)
+ self.field_map.get(field)
}
}
impl DiagnosticDeriveBuilder {
- pub fn preamble<'s>(&mut self, structure: &Structure<'s>) -> TokenStream {
+ /// Call `f` for the struct or for each variant of the enum, returning a `TokenStream` with the
+ /// tokens from `f` wrapped in an `match` expression. Emits errors for use of derive on unions
+ /// or attributes on the type itself when input is an enum.
+ pub fn each_variant<'s, F>(&mut self, structure: &mut Structure<'s>, f: F) -> TokenStream
+ where
+ F: for<'a, 'v> Fn(DiagnosticDeriveVariantBuilder<'a>, &VariantInfo<'v>) -> TokenStream,
+ {
let ast = structure.ast();
+ let span = ast.span().unwrap();
+ match ast.data {
+ syn::Data::Struct(..) | syn::Data::Enum(..) => (),
+ syn::Data::Union(..) => {
+ span_err(span, "diagnostic derives can only be used on structs and enums");
+ }
+ }
+
+ if matches!(ast.data, syn::Data::Enum(..)) {
+ for attr in &ast.attrs {
+ span_err(
+ attr.span().unwrap(),
+ "unsupported type attribute for diagnostic derive enum",
+ )
+ .emit();
+ }
+ }
+
+ structure.bind_with(|_| synstructure::BindStyle::Move);
+ let variants = structure.each_variant(|variant| {
+ let span = match structure.ast().data {
+ syn::Data::Struct(..) => span,
+ // There isn't a good way to get the span of the variant, so the variant's
+ // name will need to do.
+ _ => variant.ast().ident.span().unwrap(),
+ };
+ let builder = DiagnosticDeriveVariantBuilder {
+ parent: &self,
+ span,
+ field_map: build_field_mapping(variant),
+ formatting_init: TokenStream::new(),
+ slug: None,
+ code: None,
+ };
+ f(builder, variant)
+ });
+
+ quote! {
+ match self {
+ #variants
+ }
+ }
+ }
+}
+
+impl<'a> DiagnosticDeriveVariantBuilder<'a> {
+ /// Generates calls to `code` and similar functions based on the attributes on the type or
+ /// variant.
+ pub fn preamble<'s>(&mut self, variant: &VariantInfo<'s>) -> TokenStream {
+ let ast = variant.ast();
let attrs = &ast.attrs;
let preamble = attrs.iter().map(|attr| {
self.generate_structure_code_for_attr(attr).unwrap_or_else(|v| v.to_compile_error())
@@ -65,66 +133,48 @@ impl DiagnosticDeriveBuilder {
}
}
- pub fn body<'s>(&mut self, structure: &mut Structure<'s>) -> (TokenStream, TokenStream) {
- // Keep track of which fields need to be handled with a by-move binding.
- let mut needs_moved = std::collections::HashSet::new();
-
- // Generates calls to `span_label` and similar functions based on the attributes
- // on fields. Code for suggestions uses formatting machinery and the value of
- // other fields - because any given field can be referenced multiple times, it
- // should be accessed through a borrow. When passing fields to `add_subdiagnostic`
- // or `set_arg` (which happens below) for Fluent, we want to move the data, so that
- // has to happen in a separate pass over the fields.
- let attrs = structure
- .clone()
- .filter(|field_binding| {
- let ast = &field_binding.ast();
- !self.needs_move(ast) || {
- needs_moved.insert(field_binding.binding.clone());
- false
- }
- })
- .each(|field_binding| self.generate_field_attrs_code(field_binding));
-
- structure.bind_with(|_| synstructure::BindStyle::Move);
- // When a field has attributes like `#[label]` or `#[note]` then it doesn't
- // need to be passed as an argument to the diagnostic. But when a field has no
- // attributes or a `#[subdiagnostic]` attribute then it must be passed as an
- // argument to the diagnostic so that it can be referred to by Fluent messages.
- let args = structure
- .filter(|field_binding| needs_moved.contains(&field_binding.binding))
- .each(|field_binding| self.generate_field_attrs_code(field_binding));
-
- (attrs, args)
+ /// Generates calls to `span_label` and similar functions based on the attributes on fields or
+ /// calls to `set_arg` when no attributes are present.
+ pub fn body<'s>(&mut self, variant: &VariantInfo<'s>) -> TokenStream {
+ let mut body = quote! {};
+ // Generate `set_arg` calls first..
+ for binding in variant.bindings().iter().filter(|bi| should_generate_set_arg(bi.ast())) {
+ body.extend(self.generate_field_code(binding));
+ }
+ // ..and then subdiagnostic additions.
+ for binding in variant.bindings().iter().filter(|bi| !should_generate_set_arg(bi.ast())) {
+ body.extend(self.generate_field_attrs_code(binding));
+ }
+ body
}
- /// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic
- /// call (like `span_label`).
- fn should_generate_set_arg(&self, field: &Field) -> bool {
- field.attrs.is_empty()
- }
+ /// Parse a `SubdiagnosticKind` from an `Attribute`.
+ fn parse_subdiag_attribute(
+ &self,
+ attr: &Attribute,
+ ) -> Result<Option<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
+ let Some((subdiag, slug)) = SubdiagnosticKind::from_attr(attr, self)? else {
+ // Some attributes aren't errors - like documentation comments - but also aren't
+ // subdiagnostics.
+ return Ok(None);
+ };
- /// Returns `true` if `field` needs to have code generated in the by-move branch of the
- /// generated derive rather than the by-ref branch.
- fn needs_move(&self, field: &Field) -> bool {
- let generates_set_arg = self.should_generate_set_arg(field);
- let is_multispan = type_matches_path(&field.ty, &["rustc_errors", "MultiSpan"]);
- // FIXME(davidtwco): better support for one field needing to be in the by-move and
- // by-ref branches.
- let is_subdiagnostic = field
- .attrs
- .iter()
- .map(|attr| attr.path.segments.last().unwrap().ident.to_string())
- .any(|attr| attr == "subdiagnostic");
-
- // `set_arg` calls take their argument by-move..
- generates_set_arg
- // If this is a `MultiSpan` field then it needs to be moved to be used by any
- // attribute..
- || is_multispan
- // If this a `#[subdiagnostic]` then it needs to be moved as the other diagnostic is
- // unlikely to be `Copy`..
- || is_subdiagnostic
+ if let SubdiagnosticKind::MultipartSuggestion { .. } = subdiag {
+ let meta = attr.parse_meta()?;
+ throw_invalid_attr!(attr, &meta, |diag| diag
+ .help("consider creating a `Subdiagnostic` instead"));
+ }
+
+ let slug = slug.unwrap_or_else(|| match subdiag {
+ SubdiagnosticKind::Label => parse_quote! { _subdiag::label },
+ SubdiagnosticKind::Note => parse_quote! { _subdiag::note },
+ SubdiagnosticKind::Help => parse_quote! { _subdiag::help },
+ SubdiagnosticKind::Warn => parse_quote! { _subdiag::warn },
+ SubdiagnosticKind::Suggestion { .. } => parse_quote! { _subdiag::suggestion },
+ SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
+ });
+
+ Ok(Some((subdiag, slug)))
}
/// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
@@ -134,99 +184,70 @@ impl DiagnosticDeriveBuilder {
&mut self,
attr: &Attribute,
) -> Result<TokenStream, DiagnosticDeriveError> {
- let diag = &self.diag;
- let span = attr.span().unwrap();
+ let diag = &self.parent.diag;
+
+ // Always allow documentation comments.
+ if is_doc_comment(attr) {
+ return Ok(quote! {});
+ }
let name = attr.path.segments.last().unwrap().ident.to_string();
let name = name.as_str();
let meta = attr.parse_meta()?;
- let is_diag = name == "diag";
-
- let nested = match meta {
- // Most attributes are lists, like `#[diag(..)]` for most cases or
- // `#[help(..)]`/`#[note(..)]` when the user is specifying a alternative slug.
- Meta::List(MetaList { ref nested, .. }) => nested,
- // Subdiagnostics without spans can be applied to the type too, and these are just
- // paths: `#[help]`, `#[note]` and `#[warning]`
- Meta::Path(_) if !is_diag => {
- let fn_name = if name == "warning" {
- Ident::new("warn", attr.span())
- } else {
- Ident::new(name, attr.span())
- };
- return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::_subdiag::#fn_name); });
- }
- _ => throw_invalid_attr!(attr, &meta),
- };
-
- // Check the kind before doing any further processing so that there aren't misleading
- // "no kind specified" errors if there are failures later.
- match name {
- "error" | "lint" => throw_invalid_attr!(attr, &meta, |diag| {
- diag.help("`error` and `lint` have been replaced by `diag`")
- }),
- "warn_" => throw_invalid_attr!(attr, &meta, |diag| {
- diag.help("`warn_` have been replaced by `warning`")
- }),
- "diag" | "help" | "note" | "warning" => (),
- _ => throw_invalid_attr!(attr, &meta, |diag| {
- diag.help("only `diag`, `help`, `note` and `warning` are valid attributes")
- }),
- }
+ if name == "diag" {
+ let Meta::List(MetaList { ref nested, .. }) = meta else {
+ throw_invalid_attr!(
+ attr,
+ &meta
+ );
+ };
- // First nested element should always be the path, e.g. `#[diag(typeck::invalid)]` or
- // `#[help(typeck::another_help)]`.
- let mut nested_iter = nested.into_iter();
- if let Some(nested_attr) = nested_iter.next() {
- // Report an error if there are any other list items after the path.
- if !is_diag && nested_iter.next().is_some() {
- throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
- diag.help(
- "`help`, `note` and `warning` struct attributes can only have one argument",
- )
- });
- }
+ let mut nested_iter = nested.into_iter().peekable();
- match nested_attr {
- NestedMeta::Meta(Meta::Path(path)) => {
- if is_diag {
- self.slug.set_once((path.clone(), span));
- } else {
- let fn_name = proc_macro2::Ident::new(name, attr.span());
- return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::#path); });
- }
- }
- NestedMeta::Meta(meta @ Meta::NameValue(_))
- if is_diag && meta.path().segments.last().unwrap().ident == "code" =>
- {
- // don't error for valid follow-up attributes
+ match nested_iter.peek() {
+ Some(NestedMeta::Meta(Meta::Path(slug))) => {
+ self.slug.set_once(slug.clone(), slug.span().unwrap());
+ nested_iter.next();
}
- nested_attr => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
- diag.help("first argument of the attribute should be the diagnostic slug")
- }),
+ Some(NestedMeta::Meta(Meta::NameValue { .. })) => {}
+ Some(nested_attr) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| diag
+ .help("a diagnostic slug is required as the first argument")),
+ None => throw_invalid_attr!(attr, &meta, |diag| diag
+ .help("a diagnostic slug is required as the first argument")),
};
- }
- // Remaining attributes are optional, only `code = ".."` at the moment.
- let mut tokens = Vec::new();
- for nested_attr in nested_iter {
- let meta = match nested_attr {
- syn::NestedMeta::Meta(meta) => meta,
- _ => throw_invalid_nested_attr!(attr, &nested_attr),
- };
+ // Remaining attributes are optional, only `code = ".."` at the moment.
+ let mut tokens = TokenStream::new();
+ for nested_attr in nested_iter {
+ let (value, path) = match nested_attr {
+ NestedMeta::Meta(Meta::NameValue(MetaNameValue {
+ lit: syn::Lit::Str(value),
+ path,
+ ..
+ })) => (value, path),
+ NestedMeta::Meta(Meta::Path(_)) => {
+ invalid_nested_attr(attr, &nested_attr)
+ .help("diagnostic slug must be the first argument")
+ .emit();
+ continue;
+ }
+ _ => {
+ invalid_nested_attr(attr, &nested_attr).emit();
+ continue;
+ }
+ };
- let path = meta.path();
- let nested_name = path.segments.last().unwrap().ident.to_string();
- // Struct attributes are only allowed to be applied once, and the diagnostic
- // changes will be set in the initialisation code.
- if let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) = &meta {
- let span = s.span().unwrap();
+ let nested_name = path.segments.last().unwrap().ident.to_string();
+ // Struct attributes are only allowed to be applied once, and the diagnostic
+ // changes will be set in the initialisation code.
+ let span = value.span().unwrap();
match nested_name.as_str() {
"code" => {
- self.code.set_once((s.value(), span));
- let code = &self.code.as_ref().map(|(v, _)| v);
- tokens.push(quote! {
+ self.code.set_once((), span);
+
+ let code = value.value();
+ tokens.extend(quote! {
#diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
});
}
@@ -234,46 +255,68 @@ impl DiagnosticDeriveBuilder {
.help("only `code` is a valid nested attributes following the slug")
.emit(),
}
- } else {
- invalid_nested_attr(attr, &nested_attr).emit()
}
+ return Ok(tokens);
}
- Ok(tokens.into_iter().collect())
+ let Some((subdiag, slug)) = self.parse_subdiag_attribute(attr)? else {
+ // Some attributes aren't errors - like documentation comments - but also aren't
+ // subdiagnostics.
+ return Ok(quote! {});
+ };
+ let fn_ident = format_ident!("{}", subdiag);
+ match subdiag {
+ SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
+ Ok(self.add_subdiagnostic(&fn_ident, slug))
+ }
+ SubdiagnosticKind::Label | SubdiagnosticKind::Suggestion { .. } => {
+ throw_invalid_attr!(attr, &meta, |diag| diag
+ .help("`#[label]` and `#[suggestion]` can only be applied to fields"));
+ }
+ SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
+ }
}
- fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
+ fn generate_field_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
+ let diag = &self.parent.diag;
+
let field = binding_info.ast();
let field_binding = &binding_info.binding;
- if self.should_generate_set_arg(&field) {
- let diag = &self.diag;
- let ident = field.ident.as_ref().unwrap();
- return quote! {
- #diag.set_arg(
- stringify!(#ident),
- #field_binding
- );
- };
+ let ident = field.ident.as_ref().unwrap();
+ let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
+
+ quote! {
+ #diag.set_arg(
+ stringify!(#ident),
+ #field_binding
+ );
}
+ }
+
+ fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
+ let field = binding_info.ast();
+ let field_binding = &binding_info.binding;
- let needs_move = self.needs_move(&field);
let inner_ty = FieldInnerTy::from_type(&field.ty);
field
.attrs
.iter()
.map(move |attr| {
+ // Always allow documentation comments.
+ if is_doc_comment(attr) {
+ return quote! {};
+ }
+
let name = attr.path.segments.last().unwrap().ident.to_string();
let needs_clone =
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)
- } else if needs_move {
- (quote! { #field_binding }, true)
} else {
- (quote! { *#field_binding }, true)
+ (quote! { #field_binding }, true)
};
let generated_code = self
@@ -303,42 +346,23 @@ impl DiagnosticDeriveBuilder {
info: FieldInfo<'_>,
binding: TokenStream,
) -> Result<TokenStream, DiagnosticDeriveError> {
- let meta = attr.parse_meta()?;
- match meta {
- Meta::Path(_) => self.generate_inner_field_code_path(attr, info, binding),
- Meta::List(MetaList { .. }) => self.generate_inner_field_code_list(attr, info, binding),
- _ => throw_invalid_attr!(attr, &meta),
- }
- }
-
- fn generate_inner_field_code_path(
- &mut self,
- attr: &Attribute,
- info: FieldInfo<'_>,
- binding: TokenStream,
- ) -> Result<TokenStream, DiagnosticDeriveError> {
- assert!(matches!(attr.parse_meta()?, Meta::Path(_)));
- let diag = &self.diag;
-
+ let diag = &self.parent.diag;
let meta = attr.parse_meta()?;
let ident = &attr.path.segments.last().unwrap().ident;
let name = ident.to_string();
- let name = name.as_str();
- match name {
- "skip_arg" => {
- // Don't need to do anything - by virtue of the attribute existing, the
- // `set_arg` call will not be generated.
- Ok(quote! {})
- }
- "primary_span" => {
- match self.kind {
- DiagnosticDeriveKind::SessionDiagnostic => {
+ match (&meta, name.as_str()) {
+ // Don't need to do anything - by virtue of the attribute existing, the
+ // `set_arg` call will not be generated.
+ (Meta::Path(_), "skip_arg") => return Ok(quote! {}),
+ (Meta::Path(_), "primary_span") => {
+ match self.parent.kind {
+ DiagnosticDeriveKind::Diagnostic { .. } => {
report_error_if_not_applied_to_span(attr, &info)?;
- Ok(quote! {
+ return Ok(quote! {
#diag.set_span(#binding);
- })
+ });
}
DiagnosticDeriveKind::LintDiagnostic => {
throw_invalid_attr!(attr, &meta, |diag| {
@@ -347,188 +371,100 @@ impl DiagnosticDeriveBuilder {
}
}
}
- "label" => {
- report_error_if_not_applied_to_span(attr, &info)?;
- Ok(self.add_spanned_subdiagnostic(binding, ident, parse_quote! { _subdiag::label }))
+ (Meta::Path(_), "subdiagnostic") => {
+ return Ok(quote! { #diag.subdiagnostic(#binding); });
}
- "note" | "help" | "warning" => {
- let warn_ident = Ident::new("warn", Span::call_site());
- let (ident, path) = match name {
- "note" => (ident, parse_quote! { _subdiag::note }),
- "help" => (ident, parse_quote! { _subdiag::help }),
- "warning" => (&warn_ident, parse_quote! { _subdiag::warn }),
- _ => unreachable!(),
- };
- if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
- Ok(self.add_spanned_subdiagnostic(binding, ident, path))
- } else if type_is_unit(&info.ty) {
- Ok(self.add_subdiagnostic(ident, path))
- } else {
- report_type_error(attr, "`Span` or `()`")?
- }
+ (Meta::NameValue(_), "subdiagnostic") => {
+ throw_invalid_attr!(attr, &meta, |diag| {
+ diag.help("`eager` is the only supported nested attribute for `subdiagnostic`")
+ })
}
- "subdiagnostic" => Ok(quote! { #diag.subdiagnostic(#binding); }),
- _ => throw_invalid_attr!(attr, &meta, |diag| {
- diag.help(
- "only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` \
- are valid field attributes",
- )
- }),
- }
- }
+ (Meta::List(MetaList { ref nested, .. }), "subdiagnostic") => {
+ if nested.len() != 1 {
+ throw_invalid_attr!(attr, &meta, |diag| {
+ diag.help(
+ "`eager` is the only supported nested attribute for `subdiagnostic`",
+ )
+ })
+ }
- fn generate_inner_field_code_list(
- &mut self,
- attr: &Attribute,
- info: FieldInfo<'_>,
- binding: TokenStream,
- ) -> Result<TokenStream, DiagnosticDeriveError> {
- let meta = attr.parse_meta()?;
- let Meta::List(MetaList { ref path, ref nested, .. }) = meta else { unreachable!() };
+ let handler = match &self.parent.kind {
+ DiagnosticDeriveKind::Diagnostic { handler } => handler,
+ DiagnosticDeriveKind::LintDiagnostic => {
+ throw_invalid_attr!(attr, &meta, |diag| {
+ diag.help("eager subdiagnostics are not supported on lints")
+ })
+ }
+ };
- let ident = &attr.path.segments.last().unwrap().ident;
- let name = path.segments.last().unwrap().ident.to_string();
- let name = name.as_ref();
- match name {
- "suggestion" | "suggestion_short" | "suggestion_hidden" | "suggestion_verbose" => {
- return self.generate_inner_field_code_suggestion(attr, info);
+ let nested_attr = nested.first().expect("pop failed for single element list");
+ match nested_attr {
+ NestedMeta::Meta(meta @ Meta::Path(_))
+ if meta.path().segments.last().unwrap().ident.to_string().as_str()
+ == "eager" =>
+ {
+ return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); });
+ }
+ _ => {
+ throw_invalid_nested_attr!(attr, nested_attr, |diag| {
+ diag.help("`eager` is the only supported nested attribute for `subdiagnostic`")
+ })
+ }
+ }
}
- "label" | "help" | "note" | "warning" => (),
- _ => throw_invalid_attr!(attr, &meta, |diag| {
- diag.help(
- "only `label`, `help`, `note`, `warn` or `suggestion{,_short,_hidden,_verbose}` are \
- valid field attributes",
- )
- }),
+ _ => (),
}
- // For `#[label(..)]`, `#[note(..)]` and `#[help(..)]`, the first nested element must be a
- // path, e.g. `#[label(typeck::label)]`.
- let mut nested_iter = nested.into_iter();
- let msg = match nested_iter.next() {
- Some(NestedMeta::Meta(Meta::Path(path))) => path.clone(),
- Some(nested_attr) => throw_invalid_nested_attr!(attr, &nested_attr),
- None => throw_invalid_attr!(attr, &meta),
+ let Some((subdiag, slug)) = self.parse_subdiag_attribute(attr)? else {
+ // Some attributes aren't errors - like documentation comments - but also aren't
+ // subdiagnostics.
+ return Ok(quote! {});
};
-
- // None of these attributes should have anything following the slug.
- if nested_iter.next().is_some() {
- throw_invalid_attr!(attr, &meta);
- }
-
- match name {
- "label" => {
+ let fn_ident = format_ident!("{}", subdiag);
+ match subdiag {
+ SubdiagnosticKind::Label => {
report_error_if_not_applied_to_span(attr, &info)?;
- Ok(self.add_spanned_subdiagnostic(binding, ident, msg))
+ Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug))
}
- "note" | "help" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => {
- Ok(self.add_spanned_subdiagnostic(binding, ident, msg))
- }
- "note" | "help" if type_is_unit(&info.ty) => Ok(self.add_subdiagnostic(ident, msg)),
- // `warning` must be special-cased because the attribute `warn` already has meaning and
- // so isn't used, despite the diagnostic API being named `warn`.
- "warning" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => Ok(self
- .add_spanned_subdiagnostic(binding, &Ident::new("warn", Span::call_site()), msg)),
- "warning" if type_is_unit(&info.ty) => {
- Ok(self.add_subdiagnostic(&Ident::new("warn", Span::call_site()), msg))
- }
- "note" | "help" | "warning" => report_type_error(attr, "`Span` or `()`")?,
- _ => unreachable!(),
- }
- }
-
- fn generate_inner_field_code_suggestion(
- &mut self,
- attr: &Attribute,
- info: FieldInfo<'_>,
- ) -> Result<TokenStream, DiagnosticDeriveError> {
- let diag = &self.diag;
-
- let mut meta = attr.parse_meta()?;
- let Meta::List(MetaList { ref path, ref mut nested, .. }) = meta else { unreachable!() };
-
- let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?;
-
- let mut msg = None;
- let mut code = None;
-
- let mut nested_iter = nested.into_iter().peekable();
- if let Some(nested_attr) = nested_iter.peek() {
- if let NestedMeta::Meta(Meta::Path(path)) = nested_attr {
- msg = Some(path.clone());
+ SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
+ if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
+ Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug))
+ } else if type_is_unit(&info.ty) {
+ Ok(self.add_subdiagnostic(&fn_ident, slug))
+ } else {
+ report_type_error(attr, "`Span` or `()`")?
+ }
}
- };
- // Move the iterator forward if a path was found (don't otherwise so that
- // code/applicability can be found or an error emitted).
- if msg.is_some() {
- let _ = nested_iter.next();
- }
-
- for nested_attr in nested_iter {
- let meta = match nested_attr {
- syn::NestedMeta::Meta(ref meta) => meta,
- syn::NestedMeta::Lit(_) => throw_invalid_nested_attr!(attr, &nested_attr),
- };
-
- let nested_name = meta.path().segments.last().unwrap().ident.to_string();
- let nested_name = nested_name.as_str();
- match meta {
- Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
- let span = meta.span().unwrap();
- match nested_name {
- "code" => {
- let formatted_str = self.build_format(&s.value(), s.span());
- code = Some(formatted_str);
- }
- "applicability" => {
- applicability = match applicability {
- Some(v) => {
- span_err(
- span,
- "applicability cannot be set in both the field and \
- attribute",
- )
- .emit();
- Some(v)
- }
- None => match Applicability::from_str(&s.value()) {
- Ok(v) => Some(quote! { #v }),
- Err(()) => {
- span_err(span, "invalid applicability").emit();
- None
- }
- },
- }
- }
- _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
- diag.help(
- "only `message`, `code` and `applicability` are valid field \
- attributes",
- )
- }),
- }
+ SubdiagnosticKind::Suggestion {
+ suggestion_kind,
+ applicability: static_applicability,
+ code_field,
+ code_init,
+ } => {
+ let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?;
+
+ if let Some((static_applicability, span)) = static_applicability {
+ applicability.set_once(quote! { #static_applicability }, span);
}
- _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
- if matches!(meta, Meta::Path(_)) {
- diag.help("a diagnostic slug must be the first argument to the attribute")
- } else {
- diag
- }
- }),
+
+ let applicability = applicability
+ .value()
+ .unwrap_or_else(|| quote! { rustc_errors::Applicability::Unspecified });
+ let style = suggestion_kind.to_suggestion_style();
+
+ self.formatting_init.extend(code_init);
+ Ok(quote! {
+ #diag.span_suggestions_with_style(
+ #span_field,
+ rustc_errors::fluent::#slug,
+ #code_field,
+ #applicability,
+ #style
+ );
+ })
}
+ SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
}
-
- let applicability =
- applicability.unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
-
- let name = path.segments.last().unwrap().ident.to_string();
- let method = format_ident!("span_{}", name);
-
- let msg = msg.unwrap_or_else(|| parse_quote! { _subdiag::suggestion });
- let msg = quote! { rustc_errors::fluent::#msg };
- let code = code.unwrap_or_else(|| quote! { String::new() });
-
- Ok(quote! { #diag.#method(#span_field, #msg, #code, #applicability); })
}
/// Adds a spanned subdiagnostic by generating a `diag.span_$kind` call with the current slug
@@ -539,7 +475,7 @@ impl DiagnosticDeriveBuilder {
kind: &Ident,
fluent_attr_identifier: Path,
) -> TokenStream {
- let diag = &self.diag;
+ let diag = &self.parent.diag;
let fn_name = format_ident!("span_{}", kind);
quote! {
#diag.#fn_name(
@@ -552,7 +488,7 @@ impl DiagnosticDeriveBuilder {
/// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug
/// and `fluent_attr_identifier`.
fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: Path) -> TokenStream {
- let diag = &self.diag;
+ let diag = &self.parent.diag;
quote! {
#diag.#kind(rustc_errors::fluent::#fluent_attr_identifier);
}
@@ -561,58 +497,49 @@ impl DiagnosticDeriveBuilder {
fn span_and_applicability_of_ty(
&self,
info: FieldInfo<'_>,
- ) -> Result<(TokenStream, Option<TokenStream>), DiagnosticDeriveError> {
+ ) -> Result<(TokenStream, SpannedOption<TokenStream>), DiagnosticDeriveError> {
match &info.ty {
// If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
ty @ Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => {
let binding = &info.binding.binding;
- Ok((quote!(*#binding), None))
+ Ok((quote!(#binding), None))
}
// If `ty` is `(Span, Applicability)` then return tokens accessing those.
Type::Tuple(tup) => {
let mut span_idx = None;
let mut applicability_idx = None;
+ fn type_err(span: &Span) -> Result<!, DiagnosticDeriveError> {
+ span_err(span.unwrap(), "wrong types for suggestion")
+ .help(
+ "`#[suggestion(...)]` on a tuple field must be applied to fields \
+ of type `(Span, Applicability)`",
+ )
+ .emit();
+ Err(DiagnosticDeriveError::ErrorHandled)
+ }
+
for (idx, elem) in tup.elems.iter().enumerate() {
if type_matches_path(elem, &["rustc_span", "Span"]) {
- if span_idx.is_none() {
- span_idx = Some(syn::Index::from(idx));
- } else {
- throw_span_err!(
- info.span.unwrap(),
- "type of field annotated with `#[suggestion(...)]` contains more \
- than one `Span`"
- );
- }
+ span_idx.set_once(syn::Index::from(idx), elem.span().unwrap());
} else if type_matches_path(elem, &["rustc_errors", "Applicability"]) {
- if applicability_idx.is_none() {
- applicability_idx = Some(syn::Index::from(idx));
- } else {
- throw_span_err!(
- info.span.unwrap(),
- "type of field annotated with `#[suggestion(...)]` contains more \
- than one Applicability"
- );
- }
+ applicability_idx.set_once(syn::Index::from(idx), elem.span().unwrap());
+ } else {
+ type_err(&elem.span())?;
}
}
- if let Some(span_idx) = span_idx {
- let binding = &info.binding.binding;
- let span = quote!(#binding.#span_idx);
- let applicability = applicability_idx
- .map(|applicability_idx| quote!(#binding.#applicability_idx))
- .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
-
- return Ok((span, Some(applicability)));
- }
+ let Some((span_idx, _)) = span_idx else {
+ type_err(&tup.span())?;
+ };
+ let Some((applicability_idx, applicability_span)) = applicability_idx else {
+ type_err(&tup.span())?;
+ };
+ let binding = &info.binding.binding;
+ let span = quote!(#binding.#span_idx);
+ let applicability = quote!(#binding.#applicability_idx);
- throw_span_err!(info.span.unwrap(), "wrong types for suggestion", |diag| {
- diag.help(
- "`#[suggestion(...)]` on a tuple field must be applied to fields of type \
- `(Span, Applicability)`",
- )
- });
+ Ok((span, Some((applicability, applicability_span))))
}
// If `ty` isn't a `Span` or `(Span, Applicability)` then emit an error.
_ => throw_span_err!(info.span.unwrap(), "wrong field type for suggestion", |diag| {
diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs
index f7d8b494e..3e447c94e 100644
--- a/compiler/rustc_macros/src/diagnostics/fluent.rs
+++ b/compiler/rustc_macros/src/diagnostics/fluent.rs
@@ -25,18 +25,18 @@ use syn::{
use unic_langid::langid;
struct Resource {
- ident: Ident,
+ krate: Ident,
#[allow(dead_code)]
fat_arrow_token: token::FatArrow,
- resource: LitStr,
+ resource_path: LitStr,
}
impl Parse for Resource {
fn parse(input: ParseStream<'_>) -> Result<Self> {
Ok(Resource {
- ident: input.parse()?,
+ krate: input.parse()?,
fat_arrow_token: input.parse()?,
- resource: input.parse()?,
+ resource_path: input.parse()?,
})
}
}
@@ -94,19 +94,20 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
// diagnostics.
let mut previous_defns = HashMap::new();
+ // Set of Fluent attribute names already output, to avoid duplicate type errors - any given
+ // constant created for a given attribute is the same.
+ let mut previous_attrs = HashSet::new();
+
let mut includes = TokenStream::new();
let mut generated = TokenStream::new();
- for res in resources.0 {
- let ident_span = res.ident.span().unwrap();
- let path_span = res.resource.span().unwrap();
- // Set of Fluent attribute names already output, to avoid duplicate type errors - any given
- // constant created for a given attribute is the same.
- let mut previous_attrs = HashSet::new();
+ for res in resources.0 {
+ let krate_span = res.krate.span().unwrap();
+ let path_span = res.resource_path.span().unwrap();
- let relative_ftl_path = res.resource.value();
+ let relative_ftl_path = res.resource_path.value();
let absolute_ftl_path =
- invocation_relative_path_to_absolute(ident_span, &relative_ftl_path);
+ invocation_relative_path_to_absolute(krate_span, &relative_ftl_path);
// As this macro also outputs an `include_str!` for this file, the macro will always be
// re-executed when the file changes.
let mut resource_file = match File::open(absolute_ftl_path) {
@@ -185,7 +186,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
let mut constants = TokenStream::new();
for entry in resource.entries() {
- let span = res.ident.span();
+ let span = res.krate.span();
if let Entry::Message(Message { id: Identifier { name }, attributes, .. }) = entry {
let _ = previous_defns.entry(name.to_string()).or_insert(path_span);
@@ -199,29 +200,30 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
.emit();
}
- // `typeck_foo_bar` => `foo_bar` (in `typeck.ftl`)
- // `const_eval_baz` => `baz` (in `const_eval.ftl`)
+ // Require that the message name starts with the crate name
+ // `hir_typeck_foo_bar` (in `hir_typeck.ftl`)
+ // `const_eval_baz` (in `const_eval.ftl`)
// `const-eval-hyphen-having` => `hyphen_having` (in `const_eval.ftl`)
// The last case we error about above, but we want to fall back gracefully
// so that only the error is being emitted and not also one about the macro
// failing.
- let crate_prefix = format!("{}_", res.ident);
+ let crate_prefix = format!("{}_", res.krate);
let snake_name = name.replace('-', "_");
- let snake_name = match snake_name.strip_prefix(&crate_prefix) {
- Some(rest) => Ident::new(rest, span),
- None => {
- Diagnostic::spanned(
- path_span,
- Level::Error,
- format!("name `{name}` does not start with the crate name"),
- )
- .help(format!("prepend `{crate_prefix}` to the slug name: `{crate_prefix}{snake_name}`"))
- .emit();
- Ident::new(&snake_name, span)
- }
+ if !snake_name.starts_with(&crate_prefix) {
+ Diagnostic::spanned(
+ path_span,
+ Level::Error,
+ format!("name `{name}` does not start with the crate name"),
+ )
+ .help(format!(
+ "prepend `{crate_prefix}` to the slug name: `{crate_prefix}{snake_name}`"
+ ))
+ .emit();
};
+ let snake_name = Ident::new(&snake_name, span);
+
constants.extend(quote! {
pub const #snake_name: crate::DiagnosticMessage =
crate::DiagnosticMessage::FluentIdentifier(
@@ -275,12 +277,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
includes.extend(quote! { include_str!(#relative_ftl_path), });
- let ident = res.ident;
- generated.extend(quote! {
- pub mod #ident {
- #constants
- }
- });
+ generated.extend(constants);
}
quote! {
diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs
index 2ff21e18f..860340b43 100644
--- a/compiler/rustc_macros/src/diagnostics/mod.rs
+++ b/compiler/rustc_macros/src/diagnostics/mod.rs
@@ -5,14 +5,14 @@ mod fluent;
mod subdiagnostic;
mod utils;
-use diagnostic::{LintDiagnosticDerive, SessionDiagnosticDerive};
+use diagnostic::{DiagnosticDerive, LintDiagnosticDerive};
pub(crate) use fluent::fluent_messages;
use proc_macro2::TokenStream;
use quote::format_ident;
-use subdiagnostic::SessionSubdiagnosticDerive;
+use subdiagnostic::SubdiagnosticDeriveBuilder;
use synstructure::Structure;
-/// Implements `#[derive(SessionDiagnostic)]`, which allows for errors to be specified as a struct,
+/// Implements `#[derive(Diagnostic)]`, which allows for errors to be specified as a struct,
/// independent from the actual diagnostics emitting code.
///
/// ```ignore (rust)
@@ -22,15 +22,15 @@ use synstructure::Structure;
/// # use rustc_span::{symbol::Ident, Span};
/// # extern crate rust_middle;
/// # use rustc_middle::ty::Ty;
-/// #[derive(SessionDiagnostic)]
-/// #[diag(borrowck::move_out_of_borrow, code = "E0505")]
+/// #[derive(Diagnostic)]
+/// #[diag(borrowck_move_out_of_borrow, code = "E0505")]
/// pub struct MoveOutOfBorrowError<'tcx> {
/// pub name: Ident,
/// pub ty: Ty<'tcx>,
/// #[primary_span]
/// #[label]
/// pub span: Span,
-/// #[label(borrowck::first_borrow_label)]
+/// #[label(first_borrow_label)]
/// pub first_borrow_span: Span,
/// #[suggestion(code = "{name}.clone()")]
/// pub clone_sugg: Option<(Span, Applicability)>
@@ -56,10 +56,10 @@ use synstructure::Structure;
/// });
/// ```
///
-/// See rustc dev guide for more examples on using the `#[derive(SessionDiagnostic)]`:
+/// See rustc dev guide for more examples on using the `#[derive(Diagnostic)]`:
/// <https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html>
pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream {
- SessionDiagnosticDerive::new(format_ident!("diag"), format_ident!("sess"), s).into_tokens()
+ DiagnosticDerive::new(format_ident!("diag"), format_ident!("handler"), s).into_tokens()
}
/// Implements `#[derive(LintDiagnostic)]`, which allows for lints to be specified as a struct,
@@ -67,14 +67,14 @@ pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream {
///
/// ```ignore (rust)
/// #[derive(LintDiagnostic)]
-/// #[diag(lint::atomic_ordering_invalid_fail_success)]
+/// #[diag(lint_atomic_ordering_invalid_fail_success)]
/// pub struct AtomicOrderingInvalidLint {
/// method: Symbol,
/// success_ordering: Symbol,
/// fail_ordering: Symbol,
-/// #[label(lint::fail_label)]
+/// #[label(fail_label)]
/// fail_order_arg_span: Span,
-/// #[label(lint::success_label)]
+/// #[label(success_label)]
/// #[suggestion(
/// code = "std::sync::atomic::Ordering::{success_suggestion}",
/// applicability = "maybe-incorrect"
@@ -103,24 +103,24 @@ pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream {
/// ```
///
/// See rustc dev guide for more examples on using the `#[derive(LintDiagnostic)]`:
-/// <https://rustc-dev-guide.rust-lang.org/diagnostics/sessiondiagnostic.html>
+/// <https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html#reference>
pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
LintDiagnosticDerive::new(format_ident!("diag"), s).into_tokens()
}
-/// Implements `#[derive(SessionSubdiagnostic)]`, which allows for labels, notes, helps and
+/// Implements `#[derive(Subdiagnostic)]`, which allows for labels, notes, helps and
/// suggestions to be specified as a structs or enums, independent from the actual diagnostics
/// emitting code or diagnostic derives.
///
/// ```ignore (rust)
-/// #[derive(SessionSubdiagnostic)]
+/// #[derive(Subdiagnostic)]
/// pub enum ExpectedIdentifierLabel<'tcx> {
-/// #[label(parser::expected_identifier)]
+/// #[label(expected_identifier)]
/// WithoutFound {
/// #[primary_span]
/// span: Span,
/// }
-/// #[label(parser::expected_identifier_found)]
+/// #[label(expected_identifier_found)]
/// WithFound {
/// #[primary_span]
/// span: Span,
@@ -128,7 +128,7 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
/// }
/// }
///
-/// #[derive(SessionSubdiagnostic)]
+/// #[derive(Subdiagnostic)]
/// #[suggestion_verbose(parser::raw_identifier)]
/// pub struct RawIdentifierSuggestion<'tcx> {
/// #[primary_span]
@@ -155,5 +155,5 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
/// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident });
/// ```
pub fn session_subdiagnostic_derive(s: Structure<'_>) -> TokenStream {
- SessionSubdiagnosticDerive::new(s).into_tokens()
+ SubdiagnosticDeriveBuilder::new().into_tokens(s)
}
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index dce5d3cfb..fa0ca5a52 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -1,116 +1,35 @@
#![deny(unused_must_use)]
use crate::diagnostics::error::{
- span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, DiagnosticDeriveError,
+ invalid_attr, span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err,
+ DiagnosticDeriveError,
};
use crate::diagnostics::utils::{
- report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span,
- Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce,
+ 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,
};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
-use std::collections::HashMap;
-use std::fmt;
-use std::str::FromStr;
-use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path};
+use syn::{spanned::Spanned, Attribute, Meta, MetaList, NestedMeta, Path};
use synstructure::{BindingInfo, Structure, VariantInfo};
-/// Which kind of suggestion is being created?
-#[derive(Clone, Copy)]
-enum SubdiagnosticSuggestionKind {
- /// `#[suggestion]`
- Normal,
- /// `#[suggestion_short]`
- Short,
- /// `#[suggestion_hidden]`
- Hidden,
- /// `#[suggestion_verbose]`
- Verbose,
-}
-
-impl FromStr for SubdiagnosticSuggestionKind {
- type Err = ();
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s {
- "" => Ok(SubdiagnosticSuggestionKind::Normal),
- "_short" => Ok(SubdiagnosticSuggestionKind::Short),
- "_hidden" => Ok(SubdiagnosticSuggestionKind::Hidden),
- "_verbose" => Ok(SubdiagnosticSuggestionKind::Verbose),
- _ => Err(()),
- }
- }
-}
-
-impl SubdiagnosticSuggestionKind {
- pub fn to_suggestion_style(&self) -> TokenStream {
- match self {
- SubdiagnosticSuggestionKind::Normal => {
- quote! { rustc_errors::SuggestionStyle::ShowCode }
- }
- SubdiagnosticSuggestionKind::Short => {
- quote! { rustc_errors::SuggestionStyle::HideCodeInline }
- }
- SubdiagnosticSuggestionKind::Hidden => {
- quote! { rustc_errors::SuggestionStyle::HideCodeAlways }
- }
- SubdiagnosticSuggestionKind::Verbose => {
- quote! { rustc_errors::SuggestionStyle::ShowAlways }
- }
- }
- }
-}
-
-/// Which kind of subdiagnostic is being created from a variant?
-#[derive(Clone)]
-enum SubdiagnosticKind {
- /// `#[label(...)]`
- Label,
- /// `#[note(...)]`
- Note,
- /// `#[help(...)]`
- Help,
- /// `#[warning(...)]`
- Warn,
- /// `#[suggestion{,_short,_hidden,_verbose}]`
- Suggestion { suggestion_kind: SubdiagnosticSuggestionKind, code: TokenStream },
- /// `#[multipart_suggestion{,_short,_hidden,_verbose}]`
- MultipartSuggestion { suggestion_kind: SubdiagnosticSuggestionKind },
-}
-
-impl quote::IdentFragment for SubdiagnosticKind {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- SubdiagnosticKind::Label => write!(f, "label"),
- SubdiagnosticKind::Note => write!(f, "note"),
- SubdiagnosticKind::Help => write!(f, "help"),
- SubdiagnosticKind::Warn => write!(f, "warn"),
- SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestion_with_style"),
- SubdiagnosticKind::MultipartSuggestion { .. } => {
- write!(f, "multipart_suggestion_with_style")
- }
- }
- }
-
- fn span(&self) -> Option<proc_macro2::Span> {
- None
- }
-}
+use super::utils::{build_suggestion_code, AllowMultipleAlternatives};
/// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
-pub(crate) struct SessionSubdiagnosticDerive<'a> {
- structure: Structure<'a>,
+pub(crate) struct SubdiagnosticDeriveBuilder {
diag: syn::Ident,
+ f: syn::Ident,
}
-impl<'a> SessionSubdiagnosticDerive<'a> {
- pub(crate) fn new(structure: Structure<'a>) -> Self {
+impl SubdiagnosticDeriveBuilder {
+ pub(crate) fn new() -> Self {
let diag = format_ident!("diag");
- Self { structure, diag }
+ let f = format_ident!("f");
+ Self { diag, f }
}
- pub(crate) fn into_tokens(self) -> TokenStream {
- let SessionSubdiagnosticDerive { mut structure, diag } = self;
+ pub(crate) fn into_tokens<'a>(self, mut structure: Structure<'a>) -> TokenStream {
let implementation = {
let ast = structure.ast();
let span = ast.span().unwrap();
@@ -119,13 +38,19 @@ impl<'a> SessionSubdiagnosticDerive<'a> {
syn::Data::Union(..) => {
span_err(
span,
- "`#[derive(SessionSubdiagnostic)]` can only be used on structs and enums",
+ "`#[derive(Subdiagnostic)]` can only be used on structs and enums",
);
}
}
- if matches!(ast.data, syn::Data::Enum(..)) {
+ let is_enum = matches!(ast.data, syn::Data::Enum(..));
+ if is_enum {
for attr in &ast.attrs {
+ // Always allow documentation comments.
+ if is_doc_comment(attr) {
+ continue;
+ }
+
span_err(
attr.span().unwrap(),
"unsupported type attribute for subdiagnostic enum",
@@ -136,24 +61,16 @@ impl<'a> SessionSubdiagnosticDerive<'a> {
structure.bind_with(|_| synstructure::BindStyle::Move);
let variants_ = structure.each_variant(|variant| {
- // Build the mapping of field names to fields. This allows attributes to peek
- // values from other fields.
- let mut fields_map = HashMap::new();
- for binding in variant.bindings() {
- let field = binding.ast();
- if let Some(ident) = &field.ident {
- fields_map.insert(ident.to_string(), quote! { #binding });
- }
- }
-
- let mut builder = SessionSubdiagnosticDeriveBuilder {
- diag: &diag,
+ let mut builder = SubdiagnosticDeriveVariantBuilder {
+ parent: &self,
variant,
span,
- fields: fields_map,
+ formatting_init: TokenStream::new(),
+ fields: build_field_mapping(variant),
span_field: None,
applicability: None,
has_suggestion_parts: false,
+ is_enum,
};
builder.into_tokens().unwrap_or_else(|v| v.to_compile_error())
});
@@ -165,9 +82,17 @@ impl<'a> SessionSubdiagnosticDerive<'a> {
}
};
+ let diag = &self.diag;
+ let f = &self.f;
let ret = structure.gen_impl(quote! {
- gen impl rustc_errors::AddSubdiagnostic for @Self {
- fn add_to_diagnostic(self, #diag: &mut rustc_errors::Diagnostic) {
+ gen impl rustc_errors::AddToDiagnostic for @Self {
+ fn add_to_diagnostic_with<__F>(self, #diag: &mut rustc_errors::Diagnostic, #f: __F)
+ where
+ __F: core::ops::Fn(
+ &mut rustc_errors::Diagnostic,
+ rustc_errors::SubdiagnosticMessage
+ ) -> rustc_errors::SubdiagnosticMessage,
+ {
use rustc_errors::{Applicability, IntoDiagnosticArg};
#implementation
}
@@ -178,34 +103,40 @@ impl<'a> SessionSubdiagnosticDerive<'a> {
}
/// Tracks persistent information required for building up the call to add to the diagnostic
-/// for the final generated method. This is a separate struct to `SessionSubdiagnosticDerive`
+/// for the final generated method. This is a separate struct to `SubdiagnosticDerive`
/// only to be able to destructure and split `self.builder` and the `self.structure` up to avoid a
/// double mut borrow later on.
-struct SessionSubdiagnosticDeriveBuilder<'a> {
+struct SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
/// The identifier to use for the generated `DiagnosticBuilder` instance.
- diag: &'a syn::Ident,
+ parent: &'parent SubdiagnosticDeriveBuilder,
/// Info for the current variant (or the type if not an enum).
variant: &'a VariantInfo<'a>,
/// Span for the entire type.
span: proc_macro::Span,
+ /// Initialization of format strings for code suggestions.
+ formatting_init: TokenStream,
+
/// Store a map of field name to its corresponding field. This is built on construction of the
/// derive builder.
- fields: HashMap<String, TokenStream>,
+ fields: FieldMap,
/// Identifier for the binding to the `#[primary_span]` field.
- span_field: Option<(proc_macro2::Ident, proc_macro::Span)>,
- /// If a suggestion, the identifier for the binding to the `#[applicability]` field or a
- /// `rustc_errors::Applicability::*` variant directly.
- applicability: Option<(TokenStream, proc_macro::Span)>,
+ span_field: SpannedOption<proc_macro2::Ident>,
+
+ /// The binding to the `#[applicability]` field, if present.
+ applicability: SpannedOption<TokenStream>,
/// Set to true when a `#[suggestion_part]` field is encountered, used to generate an error
/// during finalization if still `false`.
has_suggestion_parts: bool,
+
+ /// Set to true when this variant is an enum variant rather than just the body of a struct.
+ is_enum: bool,
}
-impl<'a> HasFieldMap for SessionSubdiagnosticDeriveBuilder<'a> {
+impl<'parent, 'a> HasFieldMap for SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
self.fields.get(field)
}
@@ -217,6 +148,7 @@ struct KindsStatistics {
has_multipart_suggestion: bool,
all_multipart_suggestions: bool,
has_normal_suggestion: bool,
+ all_applicabilities_static: bool,
}
impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics {
@@ -225,8 +157,15 @@ impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics {
has_multipart_suggestion: false,
all_multipart_suggestions: true,
has_normal_suggestion: false,
+ all_applicabilities_static: true,
};
+
for kind in kinds {
+ if let SubdiagnosticKind::MultipartSuggestion { applicability: None, .. }
+ | SubdiagnosticKind::Suggestion { applicability: None, .. } = kind
+ {
+ ret.all_applicabilities_static = false;
+ }
if let SubdiagnosticKind::MultipartSuggestion { .. } = kind {
ret.has_multipart_suggestion = true;
} else {
@@ -241,134 +180,23 @@ impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics {
}
}
-impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
+impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
fn identify_kind(&mut self) -> Result<Vec<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
let mut kind_slugs = vec![];
for attr in self.variant.ast().attrs {
- let span = attr.span().unwrap();
-
- let name = attr.path.segments.last().unwrap().ident.to_string();
- let name = name.as_str();
-
- let meta = attr.parse_meta()?;
- let Meta::List(MetaList { ref nested, .. }) = meta else {
- throw_invalid_attr!(attr, &meta);
+ let Some((kind, slug)) = SubdiagnosticKind::from_attr(attr, self)? else {
+ // Some attributes aren't errors - like documentation comments - but also aren't
+ // subdiagnostics.
+ continue;
};
- let mut kind = match name {
- "label" => SubdiagnosticKind::Label,
- "note" => SubdiagnosticKind::Note,
- "help" => SubdiagnosticKind::Help,
- "warning" => SubdiagnosticKind::Warn,
- _ => {
- if let Some(suggestion_kind) =
- name.strip_prefix("suggestion").and_then(|s| s.parse().ok())
- {
- SubdiagnosticKind::Suggestion { suggestion_kind, code: TokenStream::new() }
- } else if let Some(suggestion_kind) =
- name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok())
- {
- SubdiagnosticKind::MultipartSuggestion { suggestion_kind }
- } else {
- throw_invalid_attr!(attr, &meta);
- }
- }
- };
-
- let mut slug = None;
- let mut code = None;
-
- let mut nested_iter = nested.into_iter();
- if let Some(nested_attr) = nested_iter.next() {
- match nested_attr {
- NestedMeta::Meta(Meta::Path(path)) => {
- slug.set_once((path.clone(), span));
- }
- NestedMeta::Meta(meta @ Meta::NameValue(_))
- if matches!(
- meta.path().segments.last().unwrap().ident.to_string().as_str(),
- "code" | "applicability"
- ) =>
- {
- // Don't error for valid follow-up attributes.
- }
- nested_attr => {
- throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
- diag.help(
- "first argument of the attribute should be the diagnostic \
- slug",
- )
- })
- }
- };
- }
-
- for nested_attr in nested_iter {
- let meta = match nested_attr {
- NestedMeta::Meta(ref meta) => meta,
- _ => throw_invalid_nested_attr!(attr, &nested_attr),
- };
-
- let span = meta.span().unwrap();
- let nested_name = meta.path().segments.last().unwrap().ident.to_string();
- let nested_name = nested_name.as_str();
-
- let value = match meta {
- Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => value,
- Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
- diag.help("a diagnostic slug must be the first argument to the attribute")
- }),
- _ => throw_invalid_nested_attr!(attr, &nested_attr),
- };
-
- match nested_name {
- "code" => {
- if matches!(kind, SubdiagnosticKind::Suggestion { .. }) {
- let formatted_str = self.build_format(&value.value(), value.span());
- code.set_once((formatted_str, span));
- } else {
- span_err(
- span,
- &format!(
- "`code` is not a valid nested attribute of a `{}` attribute",
- name
- ),
- )
- .emit();
- }
- }
- "applicability" => {
- if matches!(
- kind,
- SubdiagnosticKind::Suggestion { .. }
- | SubdiagnosticKind::MultipartSuggestion { .. }
- ) {
- let value =
- Applicability::from_str(&value.value()).unwrap_or_else(|()| {
- span_err(span, "invalid applicability").emit();
- Applicability::Unspecified
- });
- self.applicability.set_once((quote! { #value }, span));
- } else {
- span_err(
- span,
- &format!(
- "`applicability` is not a valid nested attribute of a `{}` attribute",
- name
- )
- ).emit();
- }
- }
- _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
- diag.help("only `code` and `applicability` are valid nested attributes")
- }),
- }
- }
+ let Some(slug) = slug else {
+ let name = attr.path.segments.last().unwrap().ident.to_string();
+ let name = name.as_str();
- let Some((slug, _)) = slug else {
throw_span_err!(
- span,
+ attr.span().unwrap(),
&format!(
"diagnostic slug must be first argument of a `#[{}(...)]` attribute",
name
@@ -376,21 +204,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
);
};
- match kind {
- SubdiagnosticKind::Suggestion { code: ref mut code_field, .. } => {
- let Some((code, _)) = code else {
- throw_span_err!(span, "suggestion without `code = \"...\"`");
- };
- *code_field = code;
- }
- SubdiagnosticKind::Label
- | SubdiagnosticKind::Note
- | SubdiagnosticKind::Help
- | SubdiagnosticKind::Warn
- | SubdiagnosticKind::MultipartSuggestion { .. } => {}
- }
-
- kind_slugs.push((kind, slug))
+ kind_slugs.push((kind, slug));
}
Ok(kind_slugs)
@@ -401,8 +215,11 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
let ast = binding.ast();
assert_eq!(ast.attrs.len(), 0, "field with attribute used as diagnostic arg");
- let diag = &self.diag;
+ let diag = &self.parent.diag;
let ident = ast.ident.as_ref().unwrap();
+ // strip `r#` prefix, if present
+ let ident = format_ident!("{}", ident);
+
quote! {
#diag.set_arg(
stringify!(#ident),
@@ -426,6 +243,11 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
ast.attrs
.iter()
.map(|attr| {
+ // Always allow documentation comments.
+ if is_doc_comment(attr) {
+ return quote! {};
+ }
+
let info = FieldInfo {
binding,
ty: inner_ty.inner_type().unwrap_or(&ast.ty),
@@ -433,7 +255,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
};
let generated = self
- .generate_field_code_inner(kind_stats, attr, info)
+ .generate_field_code_inner(kind_stats, attr, info, inner_ty.will_iterate())
.unwrap_or_else(|v| v.to_compile_error());
inner_ty.with(binding, generated)
@@ -446,13 +268,18 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
kind_stats: KindsStatistics,
attr: &Attribute,
info: FieldInfo<'_>,
+ clone_suggestion_code: bool,
) -> Result<TokenStream, DiagnosticDeriveError> {
let meta = attr.parse_meta()?;
match meta {
Meta::Path(path) => self.generate_field_code_inner_path(kind_stats, attr, info, path),
- Meta::List(list @ MetaList { .. }) => {
- self.generate_field_code_inner_list(kind_stats, attr, info, list)
- }
+ Meta::List(list @ MetaList { .. }) => self.generate_field_code_inner_list(
+ kind_stats,
+ attr,
+ info,
+ list,
+ clone_suggestion_code,
+ ),
_ => throw_invalid_attr!(attr, &meta),
}
}
@@ -474,18 +301,20 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
"skip_arg" => Ok(quote! {}),
"primary_span" => {
if kind_stats.has_multipart_suggestion {
- throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
- diag.help(
+ invalid_attr(attr, &Meta::Path(path))
+ .help(
"multipart suggestions use one or more `#[suggestion_part]`s rather \
than one `#[primary_span]`",
)
- })
- }
-
- report_error_if_not_applied_to_span(attr, &info)?;
+ .emit();
+ } else {
+ report_error_if_not_applied_to_span(attr, &info)?;
- let binding = info.binding.binding.clone();
- self.span_field.set_once((binding, span));
+ let binding = info.binding.binding.clone();
+ // FIXME(#100717): support `Option<Span>` on `primary_span` like in the
+ // diagnostic derive
+ self.span_field.set_once(binding, span);
+ }
Ok(quote! {})
}
@@ -495,28 +324,39 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
if kind_stats.has_multipart_suggestion {
span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
.emit();
- Ok(quote! {})
} else {
- throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
- diag.help(
- "`#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead",
- )
- });
+ invalid_attr(attr, &Meta::Path(path))
+ .help(
+ "`#[suggestion_part(...)]` is only valid in multipart suggestions, \
+ use `#[primary_span]` instead",
+ )
+ .emit();
}
+
+ Ok(quote! {})
}
"applicability" => {
if kind_stats.has_multipart_suggestion || kind_stats.has_normal_suggestion {
report_error_if_not_applied_to_applicability(attr, &info)?;
+ if kind_stats.all_applicabilities_static {
+ span_err(
+ span,
+ "`#[applicability]` has no effect if all `#[suggestion]`/\
+ `#[multipart_suggestion]` attributes have a static \
+ `applicability = \"...\"`",
+ )
+ .emit();
+ }
let binding = info.binding.binding.clone();
- self.applicability.set_once((quote! { #binding }, span));
+ self.applicability.set_once(quote! { #binding }, span);
} else {
span_err(span, "`#[applicability]` is only valid on suggestions").emit();
}
Ok(quote! {})
}
- _ => throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
+ _ => {
let mut span_attrs = vec![];
if kind_stats.has_multipart_suggestion {
span_attrs.push("suggestion_part");
@@ -524,11 +364,16 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
if !kind_stats.all_multipart_suggestions {
span_attrs.push("primary_span")
}
- diag.help(format!(
- "only `{}`, `applicability` and `skip_arg` are valid field attributes",
- span_attrs.join(", ")
- ))
- }),
+
+ invalid_attr(attr, &Meta::Path(path))
+ .help(format!(
+ "only `{}`, `applicability` and `skip_arg` are valid field attributes",
+ span_attrs.join(", ")
+ ))
+ .emit();
+
+ Ok(quote! {})
+ }
}
}
@@ -540,6 +385,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
attr: &Attribute,
info: FieldInfo<'_>,
list: MetaList,
+ clone_suggestion_code: bool,
) -> Result<TokenStream, DiagnosticDeriveError> {
let span = attr.span().unwrap();
let ident = &list.path.segments.last().unwrap().ident;
@@ -570,14 +416,16 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
let nested_name = meta.path().segments.last().unwrap().ident.to_string();
let nested_name = nested_name.as_str();
- let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) = meta else {
- throw_invalid_nested_attr!(attr, &nested_attr);
- };
-
match nested_name {
"code" => {
- let formatted_str = self.build_format(&value.value(), value.span());
- code.set_once((formatted_str, span));
+ let code_field = new_code_ident();
+ let formatting_init = build_suggestion_code(
+ &code_field,
+ meta,
+ self,
+ AllowMultipleAlternatives::No,
+ );
+ code.set_once((code_field, formatting_init), span);
}
_ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
diag.help("`code` is the only valid nested attribute")
@@ -585,14 +433,20 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
}
}
- let Some((code, _)) = code else {
+ let Some((code_field, formatting_init)) = code.value() else {
span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
.emit();
return Ok(quote! {});
};
let binding = info.binding;
- Ok(quote! { suggestions.push((#binding, #code)); })
+ self.formatting_init.extend(formatting_init);
+ let code_field = if clone_suggestion_code {
+ quote! { #code_field.clone() }
+ } else {
+ quote! { #code_field }
+ };
+ Ok(quote! { suggestions.push((#binding, #code_field)); })
}
_ => throw_invalid_attr!(attr, &Meta::List(list), |diag| {
let mut span_attrs = vec![];
@@ -613,10 +467,16 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
pub fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
let kind_slugs = self.identify_kind()?;
if kind_slugs.is_empty() {
- throw_span_err!(
- self.variant.ast().ident.span().unwrap(),
- "subdiagnostic kind not specified"
- );
+ if self.is_enum {
+ // It's okay for a variant to not be a subdiagnostic at all..
+ return Ok(quote! {});
+ } else {
+ // ..but structs should always be _something_.
+ throw_span_err!(
+ self.variant.ast().ident.span().unwrap(),
+ "subdiagnostic kind not specified"
+ );
+ }
};
let kind_stats: KindsStatistics = kind_slugs.iter().map(|(kind, _slug)| kind).collect();
@@ -635,29 +495,46 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
.map(|binding| self.generate_field_attr_code(binding, kind_stats))
.collect();
- let span_field = self.span_field.as_ref().map(|(span, _)| span);
- let applicability = self.applicability.take().map_or_else(
- || quote! { rustc_errors::Applicability::Unspecified },
- |(applicability, _)| applicability,
- );
+ let span_field = self.span_field.value_ref();
- let diag = &self.diag;
+ let diag = &self.parent.diag;
+ let f = &self.parent.f;
let mut calls = TokenStream::new();
for (kind, slug) in kind_slugs {
+ let message = format_ident!("__message");
+ calls.extend(quote! { let #message = #f(#diag, rustc_errors::fluent::#slug.into()); });
+
let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
- let message = quote! { rustc_errors::fluent::#slug };
let call = match kind {
- SubdiagnosticKind::Suggestion { suggestion_kind, code } => {
+ SubdiagnosticKind::Suggestion {
+ suggestion_kind,
+ applicability,
+ code_init,
+ code_field,
+ } => {
+ self.formatting_init.extend(code_init);
+
+ let applicability = applicability
+ .value()
+ .map(|a| quote! { #a })
+ .or_else(|| self.applicability.take().value())
+ .unwrap_or_else(|| quote! { rustc_errors::Applicability::Unspecified });
+
if let Some(span) = span_field {
let style = suggestion_kind.to_suggestion_style();
-
- quote! { #diag.#name(#span, #message, #code, #applicability, #style); }
+ quote! { #diag.#name(#span, #message, #code_field, #applicability, #style); }
} else {
span_err(self.span, "suggestion without `#[primary_span]` field").emit();
quote! { unreachable!(); }
}
}
- SubdiagnosticKind::MultipartSuggestion { suggestion_kind } => {
+ SubdiagnosticKind::MultipartSuggestion { suggestion_kind, applicability } => {
+ let applicability = applicability
+ .value()
+ .map(|a| quote! { #a })
+ .or_else(|| self.applicability.take().value())
+ .unwrap_or_else(|| quote! { rustc_errors::Applicability::Unspecified });
+
if !self.has_suggestion_parts {
span_err(
self.span,
@@ -686,6 +563,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
}
}
};
+
calls.extend(call);
}
@@ -697,11 +575,13 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
.map(|binding| self.generate_field_set_arg(binding))
.collect();
+ let formatting_init = &self.formatting_init;
Ok(quote! {
#init
+ #formatting_init
#attr_args
- #calls
#plain_args
+ #calls
})
}
}
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index ad9ecd39b..374c795d0 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -1,11 +1,31 @@
-use crate::diagnostics::error::{span_err, throw_span_err, DiagnosticDeriveError};
+use crate::diagnostics::error::{
+ span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, DiagnosticDeriveError,
+};
use proc_macro::Span;
-use proc_macro2::TokenStream;
+use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote, ToTokens};
+use std::cell::RefCell;
use std::collections::{BTreeSet, HashMap};
+use std::fmt;
use std::str::FromStr;
-use syn::{spanned::Spanned, Attribute, Meta, Type, TypeTuple};
-use synstructure::{BindingInfo, Structure};
+use syn::{spanned::Spanned, Attribute, Field, Meta, Type, TypeTuple};
+use syn::{MetaList, MetaNameValue, NestedMeta, Path};
+use synstructure::{BindingInfo, VariantInfo};
+
+use super::error::invalid_nested_attr;
+
+thread_local! {
+ pub static CODE_IDENT_COUNT: RefCell<u32> = RefCell::new(0);
+}
+
+/// Returns an ident of the form `__code_N` where `N` is incremented once with every call.
+pub(crate) fn new_code_ident() -> syn::Ident {
+ CODE_IDENT_COUNT.with(|count| {
+ let ident = format_ident!("__code_{}", *count.borrow());
+ *count.borrow_mut() += 1;
+ ident
+ })
+}
/// Checks whether the type name of `ty` matches `name`.
///
@@ -135,6 +155,15 @@ impl<'ty> FieldInnerTy<'ty> {
unreachable!();
}
+ /// Returns `true` if `FieldInnerTy::with` will result in iteration for this inner type (i.e.
+ /// that cloning might be required for values moved in the loop body).
+ pub(crate) fn will_iterate(&self) -> bool {
+ match self {
+ FieldInnerTy::Vec(..) => true,
+ FieldInnerTy::Option(..) | FieldInnerTy::None => false,
+ }
+ }
+
/// Returns `Option` containing inner type if there is one.
pub(crate) fn inner_type(&self) -> Option<&'ty Type> {
match self {
@@ -172,13 +201,17 @@ pub(crate) struct FieldInfo<'a> {
/// Small helper trait for abstracting over `Option` fields that contain a value and a `Span`
/// for error reporting if they are set more than once.
pub(crate) trait SetOnce<T> {
- fn set_once(&mut self, _: (T, Span));
+ fn set_once(&mut self, value: T, span: Span);
fn value(self) -> Option<T>;
+ fn value_ref(&self) -> Option<&T>;
}
-impl<T> SetOnce<T> for Option<(T, Span)> {
- fn set_once(&mut self, (value, span): (T, Span)) {
+/// An [`Option<T>`] that keeps track of the span that caused it to be set; used with [`SetOnce`].
+pub(super) type SpannedOption<T> = Option<(T, Span)>;
+
+impl<T> SetOnce<T> for SpannedOption<T> {
+ fn set_once(&mut self, value: T, span: Span) {
match self {
None => {
*self = Some((value, span));
@@ -194,8 +227,14 @@ impl<T> SetOnce<T> for Option<(T, Span)> {
fn value(self) -> Option<T> {
self.map(|(v, _)| v)
}
+
+ fn value_ref(&self) -> Option<&T> {
+ self.as_ref().map(|(v, _)| v)
+ }
}
+pub(super) type FieldMap = HashMap<String, TokenStream>;
+
pub(crate) trait HasFieldMap {
/// Returns the binding for the field with the given name, if it exists on the type.
fn get_field_binding(&self, field: &String) -> Option<&TokenStream>;
@@ -303,6 +342,7 @@ pub(crate) trait HasFieldMap {
/// `Applicability` of a suggestion - mirrors `rustc_errors::Applicability` - and used to represent
/// the user's selection of applicability if specified in an attribute.
+#[derive(Clone, Copy)]
pub(crate) enum Applicability {
MachineApplicable,
MaybeIncorrect,
@@ -345,17 +385,366 @@ impl quote::ToTokens for Applicability {
/// Build the mapping of field names to fields. This allows attributes to peek values from
/// other fields.
-pub(crate) fn build_field_mapping<'a>(structure: &Structure<'a>) -> HashMap<String, TokenStream> {
- let mut fields_map = HashMap::new();
-
- let ast = structure.ast();
- if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &ast.data {
- for field in fields.iter() {
- if let Some(ident) = &field.ident {
- fields_map.insert(ident.to_string(), quote! { &self.#ident });
+pub(super) fn build_field_mapping<'v>(variant: &VariantInfo<'v>) -> HashMap<String, TokenStream> {
+ let mut fields_map = FieldMap::new();
+ for binding in variant.bindings() {
+ if let Some(ident) = &binding.ast().ident {
+ fields_map.insert(ident.to_string(), quote! { #binding });
+ }
+ }
+ fields_map
+}
+
+#[derive(Copy, Clone, Debug)]
+pub(super) enum AllowMultipleAlternatives {
+ No,
+ Yes,
+}
+
+/// Constructs the `format!()` invocation(s) necessary for a `#[suggestion*(code = "foo")]` or
+/// `#[suggestion*(code("foo", "bar"))]` attribute field
+pub(super) fn build_suggestion_code(
+ code_field: &Ident,
+ meta: &Meta,
+ fields: &impl HasFieldMap,
+ allow_multiple: AllowMultipleAlternatives,
+) -> TokenStream {
+ let values = match meta {
+ // `code = "foo"`
+ Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => vec![s],
+ // `code("foo", "bar")`
+ Meta::List(MetaList { nested, .. }) => {
+ if let AllowMultipleAlternatives::No = allow_multiple {
+ span_err(
+ meta.span().unwrap(),
+ "expected exactly one string literal for `code = ...`",
+ )
+ .emit();
+ vec![]
+ } else if nested.is_empty() {
+ span_err(
+ meta.span().unwrap(),
+ "expected at least one string literal for `code(...)`",
+ )
+ .emit();
+ vec![]
+ } else {
+ nested
+ .into_iter()
+ .filter_map(|item| {
+ if let NestedMeta::Lit(syn::Lit::Str(s)) = item {
+ Some(s)
+ } else {
+ span_err(
+ item.span().unwrap(),
+ "`code(...)` must contain only string literals",
+ )
+ .emit();
+ None
+ }
+ })
+ .collect()
}
}
+ _ => {
+ span_err(
+ meta.span().unwrap(),
+ r#"`code = "..."`/`code(...)` must contain only string literals"#,
+ )
+ .emit();
+ vec![]
+ }
+ };
+
+ if let AllowMultipleAlternatives::Yes = allow_multiple {
+ let formatted_strings: Vec<_> = values
+ .into_iter()
+ .map(|value| fields.build_format(&value.value(), value.span()))
+ .collect();
+ quote! { let #code_field = [#(#formatted_strings),*].into_iter(); }
+ } else if let [value] = values.as_slice() {
+ let formatted_str = fields.build_format(&value.value(), value.span());
+ quote! { let #code_field = #formatted_str; }
+ } else {
+ // error handled previously
+ quote! { let #code_field = String::new(); }
}
+}
- fields_map
+/// Possible styles for suggestion subdiagnostics.
+#[derive(Clone, Copy)]
+pub(super) enum SuggestionKind {
+ /// `#[suggestion]`
+ Normal,
+ /// `#[suggestion_short]`
+ Short,
+ /// `#[suggestion_hidden]`
+ Hidden,
+ /// `#[suggestion_verbose]`
+ Verbose,
+}
+
+impl FromStr for SuggestionKind {
+ type Err = ();
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "" => Ok(SuggestionKind::Normal),
+ "_short" => Ok(SuggestionKind::Short),
+ "_hidden" => Ok(SuggestionKind::Hidden),
+ "_verbose" => Ok(SuggestionKind::Verbose),
+ _ => Err(()),
+ }
+ }
+}
+
+impl SuggestionKind {
+ pub fn to_suggestion_style(&self) -> TokenStream {
+ match self {
+ SuggestionKind::Normal => {
+ quote! { rustc_errors::SuggestionStyle::ShowCode }
+ }
+ SuggestionKind::Short => {
+ quote! { rustc_errors::SuggestionStyle::HideCodeInline }
+ }
+ SuggestionKind::Hidden => {
+ quote! { rustc_errors::SuggestionStyle::HideCodeAlways }
+ }
+ SuggestionKind::Verbose => {
+ quote! { rustc_errors::SuggestionStyle::ShowAlways }
+ }
+ }
+ }
+}
+
+/// Types of subdiagnostics that can be created using attributes
+#[derive(Clone)]
+pub(super) enum SubdiagnosticKind {
+ /// `#[label(...)]`
+ Label,
+ /// `#[note(...)]`
+ Note,
+ /// `#[help(...)]`
+ Help,
+ /// `#[warning(...)]`
+ Warn,
+ /// `#[suggestion{,_short,_hidden,_verbose}]`
+ Suggestion {
+ suggestion_kind: SuggestionKind,
+ applicability: SpannedOption<Applicability>,
+ /// Identifier for variable used for formatted code, e.g. `___code_0`. Enables separation
+ /// of formatting and diagnostic emission so that `set_arg` calls can happen in-between..
+ code_field: syn::Ident,
+ /// Initialization logic for `code_field`'s variable, e.g.
+ /// `let __formatted_code = /* whatever */;`
+ code_init: TokenStream,
+ },
+ /// `#[multipart_suggestion{,_short,_hidden,_verbose}]`
+ MultipartSuggestion {
+ suggestion_kind: SuggestionKind,
+ applicability: SpannedOption<Applicability>,
+ },
+}
+
+impl SubdiagnosticKind {
+ /// Constructs a `SubdiagnosticKind` from a field or type attribute such as `#[note]`,
+ /// `#[error(parser::add_paren)]` or `#[suggestion(code = "...")]`. Returns the
+ /// `SubdiagnosticKind` and the diagnostic slug, if specified.
+ pub(super) fn from_attr(
+ attr: &Attribute,
+ fields: &impl HasFieldMap,
+ ) -> Result<Option<(SubdiagnosticKind, Option<Path>)>, DiagnosticDeriveError> {
+ // Always allow documentation comments.
+ if is_doc_comment(attr) {
+ return Ok(None);
+ }
+
+ let span = attr.span().unwrap();
+
+ let name = attr.path.segments.last().unwrap().ident.to_string();
+ let name = name.as_str();
+
+ let meta = attr.parse_meta()?;
+ let mut kind = match name {
+ "label" => SubdiagnosticKind::Label,
+ "note" => SubdiagnosticKind::Note,
+ "help" => SubdiagnosticKind::Help,
+ "warning" => SubdiagnosticKind::Warn,
+ _ => {
+ if let Some(suggestion_kind) =
+ name.strip_prefix("suggestion").and_then(|s| s.parse().ok())
+ {
+ SubdiagnosticKind::Suggestion {
+ suggestion_kind,
+ applicability: None,
+ code_field: new_code_ident(),
+ code_init: TokenStream::new(),
+ }
+ } else if let Some(suggestion_kind) =
+ name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok())
+ {
+ SubdiagnosticKind::MultipartSuggestion { suggestion_kind, applicability: None }
+ } else {
+ throw_invalid_attr!(attr, &meta);
+ }
+ }
+ };
+
+ let nested = match meta {
+ Meta::List(MetaList { ref nested, .. }) => {
+ // An attribute with properties, such as `#[suggestion(code = "...")]` or
+ // `#[error(some::slug)]`
+ nested
+ }
+ Meta::Path(_) => {
+ // An attribute without a slug or other properties, such as `#[note]` - return
+ // without further processing.
+ //
+ // Only allow this if there are no mandatory properties, such as `code = "..."` in
+ // `#[suggestion(...)]`
+ match kind {
+ SubdiagnosticKind::Label
+ | SubdiagnosticKind::Note
+ | SubdiagnosticKind::Help
+ | SubdiagnosticKind::Warn
+ | SubdiagnosticKind::MultipartSuggestion { .. } => {
+ return Ok(Some((kind, None)));
+ }
+ SubdiagnosticKind::Suggestion { .. } => {
+ throw_span_err!(span, "suggestion without `code = \"...\"`")
+ }
+ }
+ }
+ _ => {
+ throw_invalid_attr!(attr, &meta)
+ }
+ };
+
+ let mut code = None;
+
+ let mut nested_iter = nested.into_iter().peekable();
+
+ // Peek at the first nested attribute: if it's a slug path, consume it.
+ let slug = if let Some(NestedMeta::Meta(Meta::Path(path))) = nested_iter.peek() {
+ let path = path.clone();
+ // Advance the iterator.
+ nested_iter.next();
+ Some(path)
+ } else {
+ None
+ };
+
+ for nested_attr in nested_iter {
+ let meta = match nested_attr {
+ NestedMeta::Meta(ref meta) => meta,
+ NestedMeta::Lit(_) => {
+ invalid_nested_attr(attr, &nested_attr).emit();
+ continue;
+ }
+ };
+
+ let span = meta.span().unwrap();
+ let nested_name = meta.path().segments.last().unwrap().ident.to_string();
+ let nested_name = nested_name.as_str();
+
+ let string_value = match meta {
+ Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => Some(value),
+
+ Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+ diag.help("a diagnostic slug must be the first argument to the attribute")
+ }),
+ _ => None,
+ };
+
+ match (nested_name, &mut kind) {
+ ("code", SubdiagnosticKind::Suggestion { code_field, .. }) => {
+ let code_init = build_suggestion_code(
+ code_field,
+ meta,
+ fields,
+ AllowMultipleAlternatives::Yes,
+ );
+ code.set_once(code_init, span);
+ }
+ (
+ "applicability",
+ SubdiagnosticKind::Suggestion { ref mut applicability, .. }
+ | SubdiagnosticKind::MultipartSuggestion { ref mut applicability, .. },
+ ) => {
+ let Some(value) = string_value else {
+ invalid_nested_attr(attr, &nested_attr).emit();
+ continue;
+ };
+
+ let value = Applicability::from_str(&value.value()).unwrap_or_else(|()| {
+ span_err(span, "invalid applicability").emit();
+ Applicability::Unspecified
+ });
+ applicability.set_once(value, span);
+ }
+
+ // Invalid nested attribute
+ (_, SubdiagnosticKind::Suggestion { .. }) => {
+ invalid_nested_attr(attr, &nested_attr)
+ .help("only `code` and `applicability` are valid nested attributes")
+ .emit();
+ }
+ (_, SubdiagnosticKind::MultipartSuggestion { .. }) => {
+ invalid_nested_attr(attr, &nested_attr)
+ .help("only `applicability` is a valid nested attributes")
+ .emit()
+ }
+ _ => {
+ invalid_nested_attr(attr, &nested_attr).emit();
+ }
+ }
+ }
+
+ match kind {
+ SubdiagnosticKind::Suggestion { ref code_field, ref mut code_init, .. } => {
+ *code_init = if let Some(init) = code.value() {
+ init
+ } else {
+ span_err(span, "suggestion without `code = \"...\"`").emit();
+ quote! { let #code_field = std::iter::empty(); }
+ };
+ }
+ SubdiagnosticKind::Label
+ | SubdiagnosticKind::Note
+ | SubdiagnosticKind::Help
+ | SubdiagnosticKind::Warn
+ | SubdiagnosticKind::MultipartSuggestion { .. } => {}
+ }
+
+ Ok(Some((kind, slug)))
+ }
+}
+
+impl quote::IdentFragment for SubdiagnosticKind {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ SubdiagnosticKind::Label => write!(f, "label"),
+ SubdiagnosticKind::Note => write!(f, "note"),
+ SubdiagnosticKind::Help => write!(f, "help"),
+ SubdiagnosticKind::Warn => write!(f, "warn"),
+ SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestions_with_style"),
+ SubdiagnosticKind::MultipartSuggestion { .. } => {
+ write!(f, "multipart_suggestion_with_style")
+ }
+ }
+ }
+
+ fn span(&self) -> Option<proc_macro2::Span> {
+ None
+ }
+}
+
+/// 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()
+}
+
+pub(super) fn is_doc_comment(attr: &Attribute) -> bool {
+ attr.path.segments.last().unwrap().ident.to_string() == "doc"
}
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index 2c027d754..36bda3e0f 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -1,5 +1,4 @@
#![feature(allow_internal_unstable)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(never_type)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_span)]
@@ -127,7 +126,7 @@ decl_derive!([TypeFoldable, attributes(type_foldable)] => type_foldable::type_fo
decl_derive!([TypeVisitable, attributes(type_visitable)] => type_visitable::type_visitable_derive);
decl_derive!([Lift, attributes(lift)] => lift::lift_derive);
decl_derive!(
- [SessionDiagnostic, attributes(
+ [Diagnostic, attributes(
// struct attributes
diag,
help,
@@ -161,7 +160,7 @@ decl_derive!(
suggestion_verbose)] => diagnostics::lint_diagnostic_derive
);
decl_derive!(
- [SessionSubdiagnostic, attributes(
+ [Subdiagnostic, attributes(
// struct/variant attributes
label,
help,
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index d49926c90..7cefafef9 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -237,27 +237,32 @@ fn doc_comment_from_desc(list: &Punctuated<Expr, token::Comma>) -> Result<Attrib
}
/// Add the impl of QueryDescription for the query to `impls` if one is requested
-fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStream) {
- let name = &query.name;
- let key = &query.key;
- let modifiers = &query.modifiers;
+fn add_query_desc_cached_impl(
+ query: &Query,
+ descs: &mut proc_macro2::TokenStream,
+ cached: &mut proc_macro2::TokenStream,
+) {
+ let Query { name, key, modifiers, .. } = &query;
// Find out if we should cache the query on disk
let cache = if let Some((args, expr)) = modifiers.cache.as_ref() {
let tcx = args.as_ref().map(|t| quote! { #t }).unwrap_or_else(|| quote! { _ });
// expr is a `Block`, meaning that `{ #expr }` gets expanded
// to `{ { stmts... } }`, which triggers the `unused_braces` lint.
+ // we're taking `key` by reference, but some rustc types usually prefer being passed by value
quote! {
- #[allow(unused_variables, unused_braces)]
+ #[allow(unused_variables, unused_braces, rustc::pass_by_value)]
#[inline]
- fn cache_on_disk(#tcx: TyCtxt<'tcx>, #key: &Self::Key) -> bool {
+ pub fn #name<'tcx>(#tcx: TyCtxt<'tcx>, #key: &crate::ty::query::query_keys::#name<'tcx>) -> bool {
#expr
}
}
} else {
quote! {
+ // we're taking `key` by reference, but some rustc types usually prefer being passed by value
+ #[allow(rustc::pass_by_value)]
#[inline]
- fn cache_on_disk(_: TyCtxt<'tcx>, _: &Self::Key) -> bool {
+ pub fn #name<'tcx>(_: TyCtxt<'tcx>, _: &crate::ty::query::query_keys::#name<'tcx>) -> bool {
false
}
}
@@ -268,19 +273,20 @@ fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStrea
let desc = quote! {
#[allow(unused_variables)]
- fn describe(tcx: QueryCtxt<'tcx>, key: Self::Key) -> String {
- let (#tcx, #key) = (*tcx, key);
+ pub fn #name<'tcx>(tcx: TyCtxt<'tcx>, key: crate::ty::query::query_keys::#name<'tcx>) -> String {
+ let (#tcx, #key) = (tcx, key);
::rustc_middle::ty::print::with_no_trimmed_paths!(
format!(#desc)
)
}
};
- impls.extend(quote! {
- (#name) => {
- #desc
- #cache
- };
+ descs.extend(quote! {
+ #desc
+ });
+
+ cached.extend(quote! {
+ #cache
});
}
@@ -289,7 +295,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
let mut query_stream = quote! {};
let mut query_description_stream = quote! {};
- let mut cached_queries = quote! {};
+ let mut query_cached_stream = quote! {};
for query in queries.0 {
let Query { name, arg, modifiers, .. } = &query;
@@ -299,12 +305,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
_ => quote! { #result_full },
};
- if modifiers.cache.is_some() {
- cached_queries.extend(quote! {
- #name,
- });
- }
-
let mut attributes = Vec::new();
macro_rules! passthrough {
@@ -350,7 +350,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
[#attribute_stream] fn #name(#arg) #result,
});
- add_query_description_impl(&query, &mut query_description_stream);
+ add_query_desc_cached_impl(&query, &mut query_description_stream, &mut query_cached_stream);
}
TokenStream::from(quote! {
@@ -364,9 +364,13 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
}
}
- #[macro_export]
- macro_rules! rustc_query_description {
+ pub mod descs {
+ use super::*;
#query_description_stream
}
+ pub mod cached {
+ use super::*;
+ #query_cached_stream
+ }
})
}
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index 2c5db9d8b..6d85103c9 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
libloading = "0.7.1"
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index 7d63fad32..7c387b9a9 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -3,137 +3,137 @@ use std::{
path::{Path, PathBuf},
};
-use rustc_errors::{error_code, ErrorGuaranteed};
-use rustc_macros::SessionDiagnostic;
-use rustc_session::{config, SessionDiagnostic};
+use rustc_errors::{error_code, ErrorGuaranteed, IntoDiagnostic};
+use rustc_macros::Diagnostic;
+use rustc_session::config;
use rustc_span::{sym, Span, Symbol};
use rustc_target::spec::{PanicStrategy, TargetTriple};
use crate::locator::CrateFlavor;
-#[derive(SessionDiagnostic)]
-#[diag(metadata::rlib_required)]
+#[derive(Diagnostic)]
+#[diag(metadata_rlib_required)]
pub struct RlibRequired {
pub crate_name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::lib_required)]
+#[derive(Diagnostic)]
+#[diag(metadata_lib_required)]
pub struct LibRequired<'a> {
pub crate_name: Symbol,
pub kind: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::crate_dep_multiple)]
+#[derive(Diagnostic)]
+#[diag(metadata_crate_dep_multiple)]
#[help]
pub struct CrateDepMultiple {
pub crate_name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::two_panic_runtimes)]
+#[derive(Diagnostic)]
+#[diag(metadata_two_panic_runtimes)]
pub struct TwoPanicRuntimes {
pub prev_name: Symbol,
pub cur_name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::bad_panic_strategy)]
+#[derive(Diagnostic)]
+#[diag(metadata_bad_panic_strategy)]
pub struct BadPanicStrategy {
pub runtime: Symbol,
pub strategy: PanicStrategy,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::required_panic_strategy)]
+#[derive(Diagnostic)]
+#[diag(metadata_required_panic_strategy)]
pub struct RequiredPanicStrategy {
pub crate_name: Symbol,
pub found_strategy: PanicStrategy,
pub desired_strategy: PanicStrategy,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::incompatible_panic_in_drop_strategy)]
+#[derive(Diagnostic)]
+#[diag(metadata_incompatible_panic_in_drop_strategy)]
pub struct IncompatiblePanicInDropStrategy {
pub crate_name: Symbol,
pub found_strategy: PanicStrategy,
pub desired_strategy: PanicStrategy,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::multiple_names_in_link)]
+#[derive(Diagnostic)]
+#[diag(metadata_multiple_names_in_link)]
pub struct MultipleNamesInLink {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::multiple_kinds_in_link)]
+#[derive(Diagnostic)]
+#[diag(metadata_multiple_kinds_in_link)]
pub struct MultipleKindsInLink {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::link_name_form)]
+#[derive(Diagnostic)]
+#[diag(metadata_link_name_form)]
pub struct LinkNameForm {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::link_kind_form)]
+#[derive(Diagnostic)]
+#[diag(metadata_link_kind_form)]
pub struct LinkKindForm {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::link_modifiers_form)]
+#[derive(Diagnostic)]
+#[diag(metadata_link_modifiers_form)]
pub struct LinkModifiersForm {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::link_cfg_form)]
+#[derive(Diagnostic)]
+#[diag(metadata_link_cfg_form)]
pub struct LinkCfgForm {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::wasm_import_form)]
+#[derive(Diagnostic)]
+#[diag(metadata_wasm_import_form)]
pub struct WasmImportForm {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::empty_link_name, code = "E0454")]
+#[derive(Diagnostic)]
+#[diag(metadata_empty_link_name, code = "E0454")]
pub struct EmptyLinkName {
#[primary_span]
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::link_framework_apple, code = "E0455")]
+#[derive(Diagnostic)]
+#[diag(metadata_link_framework_apple, code = "E0455")]
pub struct LinkFrameworkApple {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::framework_only_windows, code = "E0455")]
+#[derive(Diagnostic)]
+#[diag(metadata_framework_only_windows, code = "E0455")]
pub struct FrameworkOnlyWindows {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::unknown_link_kind, code = "E0458")]
+#[derive(Diagnostic)]
+#[diag(metadata_unknown_link_kind, code = "E0458")]
pub struct UnknownLinkKind<'a> {
#[primary_span]
#[label]
@@ -141,269 +141,303 @@ pub struct UnknownLinkKind<'a> {
pub kind: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::multiple_link_modifiers)]
+#[derive(Diagnostic)]
+#[diag(metadata_multiple_link_modifiers)]
pub struct MultipleLinkModifiers {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::multiple_cfgs)]
+#[derive(Diagnostic)]
+#[diag(metadata_multiple_cfgs)]
pub struct MultipleCfgs {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::link_cfg_single_predicate)]
+#[derive(Diagnostic)]
+#[diag(metadata_link_cfg_single_predicate)]
pub struct LinkCfgSinglePredicate {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::multiple_wasm_import)]
+#[derive(Diagnostic)]
+#[diag(metadata_multiple_wasm_import)]
pub struct MultipleWasmImport {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::unexpected_link_arg)]
+#[derive(Diagnostic)]
+#[diag(metadata_unexpected_link_arg)]
pub struct UnexpectedLinkArg {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::invalid_link_modifier)]
+#[derive(Diagnostic)]
+#[diag(metadata_invalid_link_modifier)]
pub struct InvalidLinkModifier {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::multiple_modifiers)]
+#[derive(Diagnostic)]
+#[diag(metadata_multiple_modifiers)]
pub struct MultipleModifiers<'a> {
#[primary_span]
pub span: Span,
pub modifier: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::bundle_needs_static)]
+#[derive(Diagnostic)]
+#[diag(metadata_bundle_needs_static)]
pub struct BundleNeedsStatic {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::whole_archive_needs_static)]
+#[derive(Diagnostic)]
+#[diag(metadata_whole_archive_needs_static)]
pub struct WholeArchiveNeedsStatic {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::as_needed_compatibility)]
+#[derive(Diagnostic)]
+#[diag(metadata_as_needed_compatibility)]
pub struct AsNeededCompatibility {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::unknown_link_modifier)]
+#[derive(Diagnostic)]
+#[diag(metadata_unknown_link_modifier)]
pub struct UnknownLinkModifier<'a> {
#[primary_span]
pub span: Span,
pub modifier: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::incompatible_wasm_link)]
+#[derive(Diagnostic)]
+#[diag(metadata_incompatible_wasm_link)]
pub struct IncompatibleWasmLink {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::link_requires_name, code = "E0459")]
+#[derive(Diagnostic)]
+#[diag(metadata_link_requires_name, code = "E0459")]
pub struct LinkRequiresName {
#[primary_span]
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::raw_dylib_no_nul)]
+#[derive(Diagnostic)]
+#[diag(metadata_raw_dylib_no_nul)]
pub struct RawDylibNoNul {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::link_ordinal_raw_dylib)]
+#[derive(Diagnostic)]
+#[diag(metadata_link_ordinal_raw_dylib)]
pub struct LinkOrdinalRawDylib {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::lib_framework_apple)]
+#[derive(Diagnostic)]
+#[diag(metadata_lib_framework_apple)]
pub struct LibFrameworkApple;
-#[derive(SessionDiagnostic)]
-#[diag(metadata::empty_renaming_target)]
+#[derive(Diagnostic)]
+#[diag(metadata_empty_renaming_target)]
pub struct EmptyRenamingTarget<'a> {
pub lib_name: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::renaming_no_link)]
+#[derive(Diagnostic)]
+#[diag(metadata_renaming_no_link)]
pub struct RenamingNoLink<'a> {
pub lib_name: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::multiple_renamings)]
+#[derive(Diagnostic)]
+#[diag(metadata_multiple_renamings)]
pub struct MultipleRenamings<'a> {
pub lib_name: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::no_link_mod_override)]
+#[derive(Diagnostic)]
+#[diag(metadata_no_link_mod_override)]
pub struct NoLinkModOverride {
#[primary_span]
pub span: Option<Span>,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::unsupported_abi_i686)]
+#[derive(Diagnostic)]
+#[diag(metadata_unsupported_abi_i686)]
pub struct UnsupportedAbiI686 {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::unsupported_abi)]
+#[derive(Diagnostic)]
+#[diag(metadata_unsupported_abi)]
pub struct UnsupportedAbi {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::fail_create_file_encoder)]
+#[derive(Diagnostic)]
+#[diag(metadata_fail_create_file_encoder)]
pub struct FailCreateFileEncoder {
pub err: Error,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::fail_seek_file)]
+#[derive(Diagnostic)]
+#[diag(metadata_fail_seek_file)]
pub struct FailSeekFile {
pub err: Error,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::fail_write_file)]
+#[derive(Diagnostic)]
+#[diag(metadata_fail_write_file)]
pub struct FailWriteFile {
pub err: Error,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::crate_not_panic_runtime)]
+#[derive(Diagnostic)]
+#[diag(metadata_crate_not_panic_runtime)]
pub struct CrateNotPanicRuntime {
pub crate_name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::no_panic_strategy)]
+#[derive(Diagnostic)]
+#[diag(metadata_no_panic_strategy)]
pub struct NoPanicStrategy {
pub crate_name: Symbol,
pub strategy: PanicStrategy,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::profiler_builtins_needs_core)]
+#[derive(Diagnostic)]
+#[diag(metadata_profiler_builtins_needs_core)]
pub struct ProfilerBuiltinsNeedsCore;
-#[derive(SessionDiagnostic)]
-#[diag(metadata::not_profiler_runtime)]
+#[derive(Diagnostic)]
+#[diag(metadata_not_profiler_runtime)]
pub struct NotProfilerRuntime {
pub crate_name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::no_multiple_global_alloc)]
+#[derive(Diagnostic)]
+#[diag(metadata_no_multiple_global_alloc)]
pub struct NoMultipleGlobalAlloc {
#[primary_span]
#[label]
pub span2: Span,
- #[label(metadata::prev_global_alloc)]
+ #[label(metadata_prev_global_alloc)]
pub span1: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::conflicting_global_alloc)]
+#[derive(Diagnostic)]
+#[diag(metadata_conflicting_global_alloc)]
pub struct ConflictingGlobalAlloc {
pub crate_name: Symbol,
pub other_crate_name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::global_alloc_required)]
+#[derive(Diagnostic)]
+#[diag(metadata_global_alloc_required)]
pub struct GlobalAllocRequired;
-#[derive(SessionDiagnostic)]
-#[diag(metadata::no_transitive_needs_dep)]
+#[derive(Diagnostic)]
+#[diag(metadata_no_transitive_needs_dep)]
pub struct NoTransitiveNeedsDep<'a> {
pub crate_name: Symbol,
pub needs_crate_name: &'a str,
pub deps_crate_name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::failed_write_error)]
+#[derive(Diagnostic)]
+#[diag(metadata_failed_write_error)]
pub struct FailedWriteError {
pub filename: PathBuf,
pub err: Error,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::missing_native_library)]
+#[derive(Diagnostic)]
+#[diag(metadata_missing_native_library)]
pub struct MissingNativeLibrary<'a> {
- pub libname: &'a str,
+ libname: &'a str,
+ #[subdiagnostic]
+ suggest_name: Option<SuggestLibraryName<'a>>,
+}
+
+impl<'a> MissingNativeLibrary<'a> {
+ pub fn new(libname: &'a str, verbatim: bool) -> Self {
+ // if it looks like the user has provided a complete filename rather just the bare lib name,
+ // then provide a note that they might want to try trimming the name
+ let suggested_name = if !verbatim {
+ if let Some(libname) = libname.strip_prefix("lib") && let Some(libname) = libname.strip_suffix(".a") {
+ // this is a unix style filename so trim prefix & suffix
+ Some(libname)
+ } else if let Some(libname) = libname.strip_suffix(".lib") {
+ // this is a Windows style filename so just trim the suffix
+ Some(libname)
+ } else {
+ None
+ }
+ } else {
+ None
+ };
+
+ Self {
+ libname,
+ suggest_name: suggested_name
+ .map(|suggested_name| SuggestLibraryName { suggested_name }),
+ }
+ }
+}
+
+#[derive(Subdiagnostic)]
+#[help(metadata_only_provide_library_name)]
+pub struct SuggestLibraryName<'a> {
+ suggested_name: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::failed_create_tempdir)]
+#[derive(Diagnostic)]
+#[diag(metadata_failed_create_tempdir)]
pub struct FailedCreateTempdir {
pub err: Error,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::failed_create_file)]
+#[derive(Diagnostic)]
+#[diag(metadata_failed_create_file)]
pub struct FailedCreateFile<'a> {
pub filename: &'a Path,
pub err: Error,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::failed_create_encoded_metadata)]
+#[derive(Diagnostic)]
+#[diag(metadata_failed_create_encoded_metadata)]
pub struct FailedCreateEncodedMetadata {
pub err: Error,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::non_ascii_name)]
+#[derive(Diagnostic)]
+#[diag(metadata_non_ascii_name)]
pub struct NonAsciiName {
#[primary_span]
pub span: Span,
pub crate_name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::extern_location_not_exist)]
+#[derive(Diagnostic)]
+#[diag(metadata_extern_location_not_exist)]
pub struct ExternLocationNotExist<'a> {
#[primary_span]
pub span: Span,
@@ -411,8 +445,8 @@ pub struct ExternLocationNotExist<'a> {
pub location: &'a Path,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::extern_location_not_file)]
+#[derive(Diagnostic)]
+#[diag(metadata_extern_location_not_file)]
pub struct ExternLocationNotFile<'a> {
#[primary_span]
pub span: Span,
@@ -427,12 +461,12 @@ pub(crate) struct MultipleCandidates {
pub candidates: Vec<PathBuf>,
}
-impl SessionDiagnostic<'_> for MultipleCandidates {
+impl IntoDiagnostic<'_> for MultipleCandidates {
fn into_diagnostic(
self,
handler: &'_ rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
- let mut diag = handler.struct_err(rustc_errors::fluent::metadata::multiple_candidates);
+ let mut diag = handler.struct_err(rustc_errors::fluent::metadata_multiple_candidates);
diag.set_arg("crate_name", self.crate_name);
diag.set_arg("flavor", self.flavor);
diag.code(error_code!(E0465));
@@ -444,8 +478,8 @@ impl SessionDiagnostic<'_> for MultipleCandidates {
}
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::multiple_matching_crates, code = "E0464")]
+#[derive(Diagnostic)]
+#[diag(metadata_multiple_matching_crates, code = "E0464")]
#[note]
pub struct MultipleMatchingCrates {
#[primary_span]
@@ -454,24 +488,24 @@ pub struct MultipleMatchingCrates {
pub candidates: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::symbol_conflicts_current, code = "E0519")]
+#[derive(Diagnostic)]
+#[diag(metadata_symbol_conflicts_current, code = "E0519")]
pub struct SymbolConflictsCurrent {
#[primary_span]
pub span: Span,
pub crate_name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::symbol_conflicts_others, code = "E0523")]
+#[derive(Diagnostic)]
+#[diag(metadata_symbol_conflicts_others, code = "E0523")]
pub struct SymbolConflictsOthers {
#[primary_span]
pub span: Span,
pub crate_name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::stable_crate_id_collision)]
+#[derive(Diagnostic)]
+#[diag(metadata_stable_crate_id_collision)]
pub struct StableCrateIdCollision {
#[primary_span]
pub span: Span,
@@ -479,18 +513,18 @@ pub struct StableCrateIdCollision {
pub crate_name1: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::dl_error)]
+#[derive(Diagnostic)]
+#[diag(metadata_dl_error)]
pub struct DlError {
#[primary_span]
pub span: Span,
pub err: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::newer_crate_version, code = "E0460")]
+#[derive(Diagnostic)]
+#[diag(metadata_newer_crate_version, code = "E0460")]
#[note]
-#[note(metadata::found_crate_versions)]
+#[note(metadata_found_crate_versions)]
pub struct NewerCrateVersion {
#[primary_span]
pub span: Span,
@@ -499,9 +533,9 @@ pub struct NewerCrateVersion {
pub found_crates: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::no_crate_with_triple, code = "E0461")]
-#[note(metadata::found_crate_versions)]
+#[derive(Diagnostic)]
+#[diag(metadata_no_crate_with_triple, code = "E0461")]
+#[note(metadata_found_crate_versions)]
pub struct NoCrateWithTriple<'a> {
#[primary_span]
pub span: Span,
@@ -511,9 +545,9 @@ pub struct NoCrateWithTriple<'a> {
pub found_crates: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::found_staticlib, code = "E0462")]
-#[note(metadata::found_crate_versions)]
+#[derive(Diagnostic)]
+#[diag(metadata_found_staticlib, code = "E0462")]
+#[note(metadata_found_crate_versions)]
#[help]
pub struct FoundStaticlib {
#[primary_span]
@@ -523,9 +557,9 @@ pub struct FoundStaticlib {
pub found_crates: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::incompatible_rustc, code = "E0514")]
-#[note(metadata::found_crate_versions)]
+#[derive(Diagnostic)]
+#[diag(metadata_incompatible_rustc, code = "E0514")]
+#[note(metadata_found_crate_versions)]
#[help]
pub struct IncompatibleRustc {
#[primary_span]
@@ -543,12 +577,12 @@ pub struct InvalidMetadataFiles {
pub crate_rejections: Vec<String>,
}
-impl SessionDiagnostic<'_> for InvalidMetadataFiles {
+impl IntoDiagnostic<'_> for InvalidMetadataFiles {
fn into_diagnostic(
self,
handler: &'_ rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
- let mut diag = handler.struct_err(rustc_errors::fluent::metadata::invalid_meta_files);
+ let mut diag = handler.struct_err(rustc_errors::fluent::metadata_invalid_meta_files);
diag.set_arg("crate_name", self.crate_name);
diag.set_arg("add_info", self.add_info);
diag.code(error_code!(E0786));
@@ -571,12 +605,12 @@ pub struct CannotFindCrate {
pub locator_triple: TargetTriple,
}
-impl SessionDiagnostic<'_> for CannotFindCrate {
+impl IntoDiagnostic<'_> for CannotFindCrate {
fn into_diagnostic(
self,
handler: &'_ rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
- let mut diag = handler.struct_err(rustc_errors::fluent::metadata::cannot_find_crate);
+ let mut diag = handler.struct_err(rustc_errors::fluent::metadata_cannot_find_crate);
diag.set_arg("crate_name", self.crate_name);
diag.set_arg("current_crate", self.current_crate);
diag.set_arg("add_info", self.add_info);
@@ -587,54 +621,54 @@ impl SessionDiagnostic<'_> for CannotFindCrate {
&& self.locator_triple != TargetTriple::from_triple(config::host_triple())
{
if self.missing_core {
- diag.note(rustc_errors::fluent::metadata::target_not_installed);
+ diag.note(rustc_errors::fluent::metadata_target_not_installed);
} else {
- diag.note(rustc_errors::fluent::metadata::target_no_std_support);
+ diag.note(rustc_errors::fluent::metadata_target_no_std_support);
}
// NOTE: this suggests using rustup, even though the user may not have it installed.
// That's because they could choose to install it; or this may give them a hint which
// target they need to install from their distro.
if self.missing_core {
- diag.help(rustc_errors::fluent::metadata::consider_downloading_target);
+ diag.help(rustc_errors::fluent::metadata_consider_downloading_target);
}
// Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway.
// NOTE: this is a dummy span if `extern crate std` was injected by the compiler.
// If it's not a dummy, that means someone added `extern crate std` explicitly and
// `#![no_std]` won't help.
if !self.missing_core && self.span.is_dummy() {
- diag.note(rustc_errors::fluent::metadata::std_required);
+ diag.note(rustc_errors::fluent::metadata_std_required);
}
if self.is_nightly_build {
- diag.help(rustc_errors::fluent::metadata::consider_building_std);
+ diag.help(rustc_errors::fluent::metadata_consider_building_std);
}
} else if self.crate_name == self.profiler_runtime {
- diag.note(rustc_errors::fluent::metadata::compiler_missing_profiler);
+ diag.note(rustc_errors::fluent::metadata_compiler_missing_profiler);
} else if self.crate_name.as_str().starts_with("rustc_") {
- diag.help(rustc_errors::fluent::metadata::install_missing_components);
+ diag.help(rustc_errors::fluent::metadata_install_missing_components);
}
- diag.span_label(self.span, rustc_errors::fluent::metadata::cant_find_crate);
+ diag.span_label(self.span, rustc_errors::fluent::metadata_cant_find_crate);
diag
}
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::no_dylib_plugin, code = "E0457")]
+#[derive(Diagnostic)]
+#[diag(metadata_no_dylib_plugin, code = "E0457")]
pub struct NoDylibPlugin {
#[primary_span]
pub span: Span,
pub crate_name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::crate_location_unknown_type)]
+#[derive(Diagnostic)]
+#[diag(metadata_crate_location_unknown_type)]
pub struct CrateLocationUnknownType<'a> {
#[primary_span]
pub span: Span,
pub path: &'a Path,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::lib_filename_form)]
+#[derive(Diagnostic)]
+#[diag(metadata_lib_filename_form)]
pub struct LibFilenameForm<'a> {
#[primary_span]
pub span: Span,
@@ -642,37 +676,37 @@ pub struct LibFilenameForm<'a> {
pub dll_suffix: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::multiple_import_name_type)]
+#[derive(Diagnostic)]
+#[diag(metadata_multiple_import_name_type)]
pub struct MultipleImportNameType {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::import_name_type_form)]
+#[derive(Diagnostic)]
+#[diag(metadata_import_name_type_form)]
pub struct ImportNameTypeForm {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::import_name_type_x86)]
+#[derive(Diagnostic)]
+#[diag(metadata_import_name_type_x86)]
pub struct ImportNameTypeX86 {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::unknown_import_name_type)]
+#[derive(Diagnostic)]
+#[diag(metadata_unknown_import_name_type)]
pub struct UnknownImportNameType<'a> {
#[primary_span]
pub span: Span,
pub import_name_type: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(metadata::import_name_type_raw)]
+#[derive(Diagnostic)]
+#[diag(metadata_import_name_type_raw)]
pub struct ImportNameTypeRaw {
#[primary_span]
pub span: Span,
diff --git a/compiler/rustc_metadata/src/foreign_modules.rs b/compiler/rustc_metadata/src/foreign_modules.rs
index 2ca4cd17f..d1c2f3104 100644
--- a/compiler/rustc_metadata/src/foreign_modules.rs
+++ b/compiler/rustc_metadata/src/foreign_modules.rs
@@ -6,13 +6,13 @@ use rustc_session::cstore::ForeignModule;
pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec<ForeignModule> {
let mut modules = Vec::new();
for id in tcx.hir().items() {
- if !matches!(tcx.def_kind(id.def_id), DefKind::ForeignMod) {
+ if !matches!(tcx.def_kind(id.owner_id), DefKind::ForeignMod) {
continue;
}
let item = tcx.hir().item(id);
if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
- let foreign_items = items.iter().map(|it| it.id.def_id.to_def_id()).collect();
- modules.push(ForeignModule { foreign_items, def_id: id.def_id.to_def_id() });
+ let foreign_items = items.iter().map(|it| it.id.owner_id.to_def_id()).collect();
+ modules.push(ForeignModule { foreign_items, def_id: id.owner_id.to_def_id() });
}
}
modules
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 6f5604b7e..98cf6fef5 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -2,10 +2,8 @@
#![feature(decl_macro)]
#![feature(drain_filter)]
#![feature(generators)]
-#![cfg_attr(bootstrap, feature(generic_associated_types))]
#![feature(iter_from_generator)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(once_cell)]
#![feature(proc_macro_internals)]
#![feature(macro_metavar_expr)]
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 257741c13..20a2e7829 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -33,29 +33,26 @@ pub fn find_native_static_library(
search_paths: &[PathBuf],
sess: &Session,
) -> PathBuf {
- let verbatim = verbatim.unwrap_or(false);
- // On Windows, static libraries sometimes show up as libfoo.a and other
- // times show up as foo.lib
- let oslibname = if verbatim {
- name.to_string()
+ let formats = if verbatim.unwrap_or(false) {
+ vec![("".into(), "".into())]
} else {
- format!("{}{}{}", sess.target.staticlib_prefix, name, sess.target.staticlib_suffix)
+ let os = (sess.target.staticlib_prefix.clone(), sess.target.staticlib_suffix.clone());
+ // On Windows, static libraries sometimes show up as libfoo.a and other
+ // times show up as foo.lib
+ let unix = ("lib".into(), ".a".into());
+ if os == unix { vec![os] } else { vec![os, unix] }
};
- let unixlibname = format!("lib{}.a", name);
for path in search_paths {
- let test = path.join(&oslibname);
- if test.exists() {
- return test;
- }
- if oslibname != unixlibname {
- let test = path.join(&unixlibname);
+ for (prefix, suffix) in &formats {
+ let test = path.join(format!("{}{}{}", prefix, name, suffix));
if test.exists() {
return test;
}
}
}
- sess.emit_fatal(MissingNativeLibrary { libname: name });
+
+ sess.emit_fatal(MissingNativeLibrary::new(name, verbatim.unwrap_or(false)));
}
fn find_bundled_library(
@@ -101,7 +98,7 @@ struct Collector<'tcx> {
impl<'tcx> Collector<'tcx> {
fn process_item(&mut self, id: rustc_hir::ItemId) {
- if !matches!(self.tcx.def_kind(id.def_id), DefKind::ForeignMod) {
+ if !matches!(self.tcx.def_kind(id.owner_id), DefKind::ForeignMod) {
return;
}
@@ -375,17 +372,17 @@ impl<'tcx> Collector<'tcx> {
}
_ => {
for child_item in foreign_mod_items {
- if self.tcx.def_kind(child_item.id.def_id).has_codegen_attrs()
+ if self.tcx.def_kind(child_item.id.owner_id).has_codegen_attrs()
&& self
.tcx
- .codegen_fn_attrs(child_item.id.def_id)
+ .codegen_fn_attrs(child_item.id.owner_id)
.link_ordinal
.is_some()
{
let link_ordinal_attr = self
.tcx
.hir()
- .attrs(self.tcx.hir().local_def_id_to_hir_id(child_item.id.def_id))
+ .attrs(child_item.id.owner_id.into())
.iter()
.find(|a| a.has_name(sym::link_ordinal))
.unwrap();
@@ -405,7 +402,7 @@ impl<'tcx> Collector<'tcx> {
filename,
kind,
cfg,
- foreign_module: Some(it.def_id.to_def_id()),
+ foreign_module: Some(it.owner_id.to_def_id()),
wasm_import_module: wasm_import_module.map(|(name, _)| name),
verbatim,
dll_imports,
@@ -508,7 +505,7 @@ impl<'tcx> Collector<'tcx> {
fn i686_arg_list_size(&self, item: &hir::ForeignItemRef) -> usize {
let argument_types: &List<Ty<'_>> = self.tcx.erase_late_bound_regions(
self.tcx
- .type_of(item.id.def_id)
+ .type_of(item.id.owner_id)
.fn_sig(self.tcx)
.inputs()
.map_bound(|slice| self.tcx.mk_type_list(slice.iter())),
@@ -560,7 +557,7 @@ impl<'tcx> Collector<'tcx> {
}
};
- let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item.id.def_id);
+ let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item.id.owner_id);
let import_name_type = codegen_fn_attrs
.link_ordinal
.map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord)));
@@ -570,7 +567,7 @@ impl<'tcx> Collector<'tcx> {
import_name_type,
calling_convention,
span: item.span,
- is_fn: self.tcx.def_kind(item.id.def_id).is_fn_like(),
+ is_fn: self.tcx.def_kind(item.id.owner_id).is_fn_like(),
}
}
}
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 830417eea..691e3d0f8 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -773,7 +773,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
}
fn opt_item_name(self, item_index: DefIndex) -> Option<Symbol> {
- self.def_key(item_index).disambiguated_data.data.get_opt_name()
+ let def_key = self.def_key(item_index);
+ def_key.disambiguated_data.data.get_opt_name().or_else(|| {
+ if def_key.disambiguated_data.data == DefPathData::Ctor {
+ let parent_index = def_key.parent.expect("no parent for a constructor");
+ self.def_key(parent_index).disambiguated_data.data.get_opt_name()
+ } else {
+ None
+ }
+ })
}
fn item_name(self, item_index: DefIndex) -> Symbol {
@@ -905,7 +913,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
.get(self, item_id)
.unwrap_or_else(LazyArray::empty)
.decode(self)
- .map(|index| self.get_variant(&self.def_kind(index), index, did))
+ .filter_map(|index| {
+ let kind = self.def_kind(index);
+ match kind {
+ DefKind::Ctor(..) => None,
+ _ => Some(self.get_variant(&kind, index, did)),
+ }
+ })
.collect()
} else {
std::iter::once(self.get_variant(&kind, item_id, did)).collect()
@@ -1029,50 +1043,27 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
callback(ModChild { ident, res, vis, span, macro_rules });
- // For non-re-export structs and variants add their constructors to children.
- // Re-export lists automatically contain constructors when necessary.
- match kind {
- DefKind::Struct => {
- if let Some((ctor_def_id, ctor_kind)) =
- self.get_ctor_def_id_and_kind(child_index)
- {
- let ctor_res =
- Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
- let vis = self.get_visibility(ctor_def_id.index);
- callback(ModChild {
- ident,
- res: ctor_res,
- vis,
- span,
- macro_rules: false,
- });
- }
- }
- DefKind::Variant => {
- // Braced variants, unlike structs, generate unusable names in
- // value namespace, they are reserved for possible future use.
- // It's ok to use the variant's id as a ctor id since an
- // error will be reported on any use of such resolution anyway.
- let (ctor_def_id, ctor_kind) = self
- .get_ctor_def_id_and_kind(child_index)
- .unwrap_or((def_id, CtorKind::Fictive));
- let ctor_res =
- Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
- let mut vis = self.get_visibility(ctor_def_id.index);
- if ctor_def_id == def_id && vis.is_public() {
- // For non-exhaustive variants lower the constructor visibility to
- // within the crate. We only need this for fictive constructors,
- // for other constructors correct visibilities
- // were already encoded in metadata.
- let mut attrs = self.get_item_attrs(def_id.index, sess);
- if attrs.any(|item| item.has_name(sym::non_exhaustive)) {
- let crate_def_id = self.local_def_id(CRATE_DEF_INDEX);
- vis = ty::Visibility::Restricted(crate_def_id);
- }
+ // For non-reexport variants add their fictive constructors to children.
+ // Braced variants, unlike structs, generate unusable names in value namespace,
+ // they are reserved for possible future use. It's ok to use the variant's id as
+ // a ctor id since an error will be reported on any use of such resolution anyway.
+ // Reexport lists automatically contain such constructors when necessary.
+ if kind == DefKind::Variant && self.get_ctor_def_id_and_kind(child_index).is_none()
+ {
+ let ctor_res =
+ Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fictive), def_id);
+ let mut vis = vis;
+ if vis.is_public() {
+ // For non-exhaustive variants lower the constructor visibility to
+ // within the crate. We only need this for fictive constructors,
+ // for other constructors correct visibilities
+ // were already encoded in metadata.
+ let mut attrs = self.get_item_attrs(def_id.index, sess);
+ if attrs.any(|item| item.has_name(sym::non_exhaustive)) {
+ vis = ty::Visibility::Restricted(self.local_def_id(CRATE_DEF_INDEX));
}
- callback(ModChild { ident, res: ctor_res, vis, span, macro_rules: false });
}
- _ => {}
+ callback(ModChild { ident, res: ctor_res, vis, span, macro_rules: false });
}
}
}
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index dede1b212..a0a085525 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -15,7 +15,6 @@ use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, TyCtxt, Visibility};
use rustc_session::cstore::{CrateSource, CrateStore};
-use rustc_session::utils::NativeLibKind;
use rustc_session::{Session, StableCrateId};
use rustc_span::hygiene::{ExpnHash, ExpnId};
use rustc_span::source_map::{Span, Spanned};
@@ -210,6 +209,7 @@ provide! { tcx, def_id, other, cdata,
lookup_const_stability => { table }
lookup_default_body_stability => { table }
lookup_deprecation_entry => { table }
+ params_in_repr => { table }
unused_generic_params => { table }
opt_def_kind => { table_direct }
impl_parent => { table }
@@ -223,6 +223,16 @@ provide! { tcx, def_id, other, cdata,
fn_arg_names => { table }
generator_kind => { table }
trait_def => { table }
+ deduced_param_attrs => { table }
+ collect_trait_impl_trait_tys => {
+ Ok(cdata
+ .root
+ .tables
+ .trait_impl_trait_tys
+ .get(cdata, def_id.index)
+ .map(|lazy| lazy.decode((cdata, tcx)))
+ .process_decoded(tcx, || panic!("{:?} does not have trait_impl_trait_tys", def_id)))
+ }
visibility => { cdata.get_visibility(def_id.index) }
adt_def => { cdata.get_adt_def(def_id.index, tcx) }
@@ -329,20 +339,10 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
// resolve! Does this work? Unsure! That's what the issue is about
*providers = Providers {
allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(),
- is_dllimport_foreign_item: |tcx, id| match tcx.native_library_kind(id) {
- Some(
- NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified,
- ) => true,
- _ => false,
- },
- is_statically_included_foreign_item: |tcx, id| {
- matches!(tcx.native_library_kind(id), Some(NativeLibKind::Static { .. }))
- },
is_private_dep: |_tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
false
},
- native_library_kind: |tcx, id| tcx.native_library(id).map(|l| l.kind),
native_library: |tcx, id| {
tcx.native_libraries(id.krate)
.iter()
@@ -587,11 +587,6 @@ impl CStore {
self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess)
}
- /// Decodes all traits in the crate (for rustdoc).
- pub fn traits_in_crate_untracked(&self, cnum: CrateNum) -> impl Iterator<Item = DefId> + '_ {
- self.get_crate_data(cnum).get_traits()
- }
-
/// Decodes all trait impls in the crate (for rustdoc).
pub fn trait_impls_in_crate_untracked(
&self,
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 5a60ea794..049514ec7 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -3,6 +3,7 @@ use crate::rmeta::def_path_hash_map::DefPathHashMapRef;
use crate::rmeta::table::TableBuilder;
use crate::rmeta::*;
+use rustc_ast::Attribute;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::memmap::{Mmap, MmapMut};
@@ -28,8 +29,9 @@ 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};
-use rustc_session::config::CrateType;
+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};
@@ -261,10 +263,10 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
// This allows us to avoid loading the dependencies of proc-macro crates: all of
// the information we need to decode `Span`s is stored in the proc-macro crate.
let (tag, metadata_index) = if source_file.is_imported() && !s.is_proc_macro {
- // To simplify deserialization, we 'rebase' this span onto the crate it originally came from
- // (the crate that 'owns' the file it references. These rebased 'lo' and 'hi' values
- // are relative to the source map information for the 'foreign' crate whose CrateNum
- // we write into the metadata. This allows `imported_source_files` to binary
+ // To simplify deserialization, we 'rebase' this span onto the crate it originally came
+ // from (the crate that 'owns' the file it references. These rebased 'lo' and 'hi'
+ // values are relative to the source map information for the 'foreign' crate whose
+ // CrateNum we write into the metadata. This allows `imported_source_files` to binary
// search through the 'foreign' crate's source map information, using the
// deserialized 'lo' and 'hi' values directly.
//
@@ -554,78 +556,56 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_crate_root(&mut self) -> LazyValue<CrateRoot> {
let tcx = self.tcx;
- let mut i = 0;
- let preamble_bytes = self.position() - i;
-
- // Encode the crate deps
- i = self.position();
- let crate_deps = self.encode_crate_deps();
- let dylib_dependency_formats = self.encode_dylib_dependency_formats();
- let dep_bytes = self.position() - i;
-
- // Encode the lib features.
- i = self.position();
- let lib_features = self.encode_lib_features();
- let lib_feature_bytes = self.position() - i;
-
- // Encode the stability implications.
- i = self.position();
- let stability_implications = self.encode_stability_implications();
- let stability_implications_bytes = self.position() - i;
-
- // Encode the language items.
- i = self.position();
- let lang_items = self.encode_lang_items();
- let lang_items_missing = self.encode_lang_items_missing();
- let lang_item_bytes = self.position() - i;
-
- // Encode the diagnostic items.
- i = self.position();
- let diagnostic_items = self.encode_diagnostic_items();
- let diagnostic_item_bytes = self.position() - i;
-
- // Encode the native libraries used
- i = self.position();
- let native_libraries = self.encode_native_libraries();
- let native_lib_bytes = self.position() - i;
-
- i = self.position();
- let foreign_modules = self.encode_foreign_modules();
- let foreign_modules_bytes = self.position() - i;
-
- // Encode DefPathTable
- i = self.position();
- self.encode_def_path_table();
- let def_path_table_bytes = self.position() - i;
+ let mut stats: Vec<(&'static str, usize)> = Vec::with_capacity(32);
+
+ macro_rules! stat {
+ ($label:literal, $f:expr) => {{
+ let orig_pos = self.position();
+ let res = $f();
+ stats.push(($label, self.position() - orig_pos));
+ res
+ }};
+ }
+
+ // We have already encoded some things. Get their combined size from the current position.
+ stats.push(("preamble", self.position()));
+
+ let (crate_deps, dylib_dependency_formats) =
+ stat!("dep", || (self.encode_crate_deps(), self.encode_dylib_dependency_formats()));
+
+ let lib_features = stat!("lib-features", || self.encode_lib_features());
+
+ let stability_implications =
+ stat!("stability-implications", || self.encode_stability_implications());
+
+ let (lang_items, lang_items_missing) = stat!("lang-items", || {
+ (self.encode_lang_items(), self.encode_lang_items_missing())
+ });
+
+ let diagnostic_items = stat!("diagnostic-items", || self.encode_diagnostic_items());
+
+ let native_libraries = stat!("native-libs", || self.encode_native_libraries());
+
+ let foreign_modules = stat!("foreign-modules", || self.encode_foreign_modules());
+
+ _ = stat!("def-path-table", || self.encode_def_path_table());
// Encode the def IDs of traits, for rustdoc and diagnostics.
- i = self.position();
- let traits = self.encode_traits();
- let traits_bytes = self.position() - i;
+ let traits = stat!("traits", || self.encode_traits());
// Encode the def IDs of impls, for coherence checking.
- i = self.position();
- let impls = self.encode_impls();
- let impls_bytes = self.position() - i;
-
- i = self.position();
- let incoherent_impls = self.encode_incoherent_impls();
- let incoherent_impls_bytes = self.position() - i;
-
- // Encode MIR.
- i = self.position();
- self.encode_mir();
- let mir_bytes = self.position() - i;
-
- // Encode the items.
- i = self.position();
- self.encode_def_ids();
- self.encode_info_for_items();
- let item_bytes = self.position() - i;
-
- // Encode the allocation index
- i = self.position();
- let interpret_alloc_index = {
+ let impls = stat!("impls", || self.encode_impls());
+
+ let incoherent_impls = stat!("incoherent-impls", || self.encode_incoherent_impls());
+
+ _ = stat!("mir", || self.encode_mir());
+
+ _ = stat!("items", || {
+ self.encode_def_ids();
+ self.encode_info_for_items();
+ });
+
+ let interpret_alloc_index = stat!("interpret-alloc-index", || {
let mut interpret_alloc_index = Vec::new();
let mut n = 0;
trace!("beginning to encode alloc ids");
@@ -646,126 +626,90 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
n = new_n;
}
self.lazy_array(interpret_alloc_index)
- };
- let interpret_alloc_index_bytes = self.position() - i;
+ });
- // Encode the proc macro data. This affects 'tables',
- // so we need to do this before we encode the tables.
- // This overwrites def_keys, so it must happen after encode_def_path_table.
- i = self.position();
- let proc_macro_data = self.encode_proc_macros();
- let proc_macro_data_bytes = self.position() - i;
+ // Encode the proc macro data. This affects `tables`, so we need to do this before we
+ // encode the tables. This overwrites def_keys, so it must happen after
+ // encode_def_path_table.
+ let proc_macro_data = stat!("proc-macro-data", || self.encode_proc_macros());
- i = self.position();
- let tables = self.tables.encode(&mut self.opaque);
- let tables_bytes = self.position() - i;
+ let tables = stat!("tables", || self.tables.encode(&mut self.opaque));
- i = self.position();
- let debugger_visualizers = self.encode_debugger_visualizers();
- let debugger_visualizers_bytes = self.position() - i;
+ let debugger_visualizers =
+ stat!("debugger-visualizers", || self.encode_debugger_visualizers());
// Encode exported symbols info. This is prefetched in `encode_metadata` so we encode
// this as late as possible to give the prefetching as much time as possible to complete.
- i = self.position();
- let exported_symbols = tcx.exported_symbols(LOCAL_CRATE);
- let exported_symbols = self.encode_exported_symbols(&exported_symbols);
- let exported_symbols_bytes = self.position() - i;
-
- // Encode the hygiene data,
- // IMPORTANT: this *must* be the last thing that we encode (other than `SourceMap`). The process
- // of encoding other items (e.g. `optimized_mir`) may cause us to load
- // data from the incremental cache. If this causes us to deserialize a `Span`,
- // then we may load additional `SyntaxContext`s into the global `HygieneData`.
- // Therefore, we need to encode the hygiene data last to ensure that we encode
- // any `SyntaxContext`s that might be used.
- i = self.position();
- let (syntax_contexts, expn_data, expn_hashes) = self.encode_hygiene();
- let hygiene_bytes = self.position() - i;
-
- i = self.position();
- let def_path_hash_map = self.encode_def_path_hash_map();
- let def_path_hash_map_bytes = self.position() - i;
-
- // Encode source_map. This needs to be done last,
- // since encoding `Span`s tells us which `SourceFiles` we actually
- // need to encode.
- i = self.position();
- let source_map = self.encode_source_map();
- let source_map_bytes = self.position() - i;
-
- i = self.position();
- let attrs = tcx.hir().krate_attrs();
- let has_default_lib_allocator = tcx.sess.contains_name(&attrs, sym::default_lib_allocator);
- let root = self.lazy(CrateRoot {
- name: tcx.crate_name(LOCAL_CRATE),
- extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
- triple: tcx.sess.opts.target_triple.clone(),
- hash: tcx.crate_hash(LOCAL_CRATE),
- stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(),
- required_panic_strategy: tcx.required_panic_strategy(LOCAL_CRATE),
- panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop,
- edition: tcx.sess.edition(),
- has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
- has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
- has_default_lib_allocator,
- proc_macro_data,
- debugger_visualizers,
- compiler_builtins: tcx.sess.contains_name(&attrs, sym::compiler_builtins),
- needs_allocator: tcx.sess.contains_name(&attrs, sym::needs_allocator),
- needs_panic_runtime: tcx.sess.contains_name(&attrs, sym::needs_panic_runtime),
- no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins),
- panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime),
- profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime),
- symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(),
-
- crate_deps,
- dylib_dependency_formats,
- lib_features,
- stability_implications,
- lang_items,
- diagnostic_items,
- lang_items_missing,
- native_libraries,
- foreign_modules,
- source_map,
- traits,
- impls,
- incoherent_impls,
- exported_symbols,
- interpret_alloc_index,
- tables,
- syntax_contexts,
- expn_data,
- expn_hashes,
- def_path_hash_map,
+ let exported_symbols = stat!("exported-symbols", || {
+ self.encode_exported_symbols(&tcx.exported_symbols(LOCAL_CRATE))
+ });
+
+ // Encode the hygiene data.
+ // IMPORTANT: this *must* be the last thing that we encode (other than `SourceMap`). The
+ // process of encoding other items (e.g. `optimized_mir`) may cause us to load data from
+ // the incremental cache. If this causes us to deserialize a `Span`, then we may load
+ // additional `SyntaxContext`s into the global `HygieneData`. Therefore, we need to encode
+ // the hygiene data last to ensure that we encode any `SyntaxContext`s that might be used.
+ let (syntax_contexts, expn_data, expn_hashes) = stat!("hygiene", || self.encode_hygiene());
+
+ let def_path_hash_map = stat!("def-path-hash-map", || self.encode_def_path_hash_map());
+
+ // Encode source_map. This needs to be done last, because encoding `Span`s tells us which
+ // `SourceFiles` we actually need to encode.
+ let source_map = stat!("source-map", || self.encode_source_map());
+
+ let root = stat!("final", || {
+ let attrs = tcx.hir().krate_attrs();
+ self.lazy(CrateRoot {
+ name: tcx.crate_name(LOCAL_CRATE),
+ extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
+ triple: tcx.sess.opts.target_triple.clone(),
+ hash: tcx.crate_hash(LOCAL_CRATE),
+ stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(),
+ required_panic_strategy: tcx.required_panic_strategy(LOCAL_CRATE),
+ panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop,
+ edition: tcx.sess.edition(),
+ has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
+ has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
+ has_default_lib_allocator: tcx
+ .sess
+ .contains_name(&attrs, sym::default_lib_allocator),
+ proc_macro_data,
+ debugger_visualizers,
+ compiler_builtins: tcx.sess.contains_name(&attrs, sym::compiler_builtins),
+ needs_allocator: tcx.sess.contains_name(&attrs, sym::needs_allocator),
+ needs_panic_runtime: tcx.sess.contains_name(&attrs, sym::needs_panic_runtime),
+ no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins),
+ panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime),
+ profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime),
+ symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(),
+
+ crate_deps,
+ dylib_dependency_formats,
+ lib_features,
+ stability_implications,
+ lang_items,
+ diagnostic_items,
+ lang_items_missing,
+ native_libraries,
+ foreign_modules,
+ source_map,
+ traits,
+ impls,
+ incoherent_impls,
+ exported_symbols,
+ interpret_alloc_index,
+ tables,
+ syntax_contexts,
+ expn_data,
+ expn_hashes,
+ def_path_hash_map,
+ })
});
- let final_bytes = self.position() - i;
let total_bytes = self.position();
- let computed_total_bytes = preamble_bytes
- + dep_bytes
- + lib_feature_bytes
- + stability_implications_bytes
- + lang_item_bytes
- + diagnostic_item_bytes
- + native_lib_bytes
- + foreign_modules_bytes
- + def_path_table_bytes
- + traits_bytes
- + impls_bytes
- + incoherent_impls_bytes
- + mir_bytes
- + item_bytes
- + interpret_alloc_index_bytes
- + proc_macro_data_bytes
- + tables_bytes
- + debugger_visualizers_bytes
- + exported_symbols_bytes
- + hygiene_bytes
- + def_path_hash_map_bytes
- + source_map_bytes
- + final_bytes;
+ let computed_total_bytes: usize = stats.iter().map(|(_, size)| size).sum();
assert_eq!(total_bytes, computed_total_bytes);
if tcx.sess.meta_stats() {
@@ -783,48 +727,77 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
assert_eq!(self.opaque.file().stream_position().unwrap(), pos_before_rewind);
+ stats.sort_by_key(|&(_, usize)| usize);
+
+ let prefix = "meta-stats";
let perc = |bytes| (bytes * 100) as f64 / total_bytes as f64;
- let p = |label, bytes| {
- eprintln!("{:>21}: {:>8} bytes ({:4.1}%)", label, bytes, perc(bytes));
- };
- eprintln!("");
+ eprintln!("{} METADATA STATS", prefix);
+ eprintln!("{} {:<23}{:>10}", prefix, "Section", "Size");
+ eprintln!(
+ "{} ----------------------------------------------------------------",
+ prefix
+ );
+ for (label, size) in stats {
+ eprintln!(
+ "{} {:<23}{:>10} ({:4.1}%)",
+ prefix,
+ label,
+ to_readable_str(size),
+ perc(size)
+ );
+ }
+ eprintln!(
+ "{} ----------------------------------------------------------------",
+ prefix
+ );
eprintln!(
- "{} metadata bytes, of which {} bytes ({:.1}%) are zero",
- total_bytes,
- zero_bytes,
+ "{} {:<23}{:>10} (of which {:.1}% are zero bytes)",
+ prefix,
+ "Total",
+ to_readable_str(total_bytes),
perc(zero_bytes)
);
- p("preamble", preamble_bytes);
- p("dep", dep_bytes);
- p("lib feature", lib_feature_bytes);
- p("stability_implications", stability_implications_bytes);
- p("lang item", lang_item_bytes);
- p("diagnostic item", diagnostic_item_bytes);
- p("native lib", native_lib_bytes);
- p("foreign modules", foreign_modules_bytes);
- p("def-path table", def_path_table_bytes);
- p("traits", traits_bytes);
- p("impls", impls_bytes);
- p("incoherent_impls", incoherent_impls_bytes);
- p("mir", mir_bytes);
- p("item", item_bytes);
- p("interpret_alloc_index", interpret_alloc_index_bytes);
- p("proc-macro-data", proc_macro_data_bytes);
- p("tables", tables_bytes);
- p("debugger visualizers", debugger_visualizers_bytes);
- p("exported symbols", exported_symbols_bytes);
- p("hygiene", hygiene_bytes);
- p("def-path hashes", def_path_hash_map_bytes);
- p("source_map", source_map_bytes);
- p("final", final_bytes);
- eprintln!("");
+ eprintln!("{}", prefix);
}
root
}
}
+/// Returns whether an attribute needs to be recorded in metadata, that is, if it's usable and
+/// useful in downstream crates. Local-only attributes are an obvious example, but some
+/// rustdoc-specific attributes can equally be of use while documenting the current crate only.
+///
+/// Removing these superfluous attributes speeds up compilation by making the metadata smaller.
+///
+/// Note: the `is_def_id_public` parameter is used to cache whether the given `DefId` has a public
+/// visibility: this is a piece of data that can be computed once per defid, and not once per
+/// attribute. Some attributes would only be usable downstream if they are public.
+#[inline]
+fn should_encode_attr(
+ tcx: TyCtxt<'_>,
+ attr: &Attribute,
+ def_id: LocalDefId,
+ is_def_id_public: &mut Option<bool>,
+) -> bool {
+ if rustc_feature::is_builtin_only_local(attr.name_or_empty()) {
+ // Attributes marked local-only don't need to be encoded for downstream crates.
+ false
+ } else if attr.doc_str().is_some() {
+ // We keep all public doc comments because they might be "imported" into downstream crates
+ // if they use `#[doc(inline)]` to copy an item's documentation into their own.
+ *is_def_id_public
+ .get_or_insert_with(|| tcx.effective_visibilities(()).effective_vis(def_id).is_some())
+ } else if attr.has_name(sym::doc) {
+ // If this is a `doc` attribute, and it's marked `inline` (as in `#[doc(inline)]`), we can
+ // remove it. It won't be inlinable in downstream crates.
+ attr.meta_item_list().map(|l| l.iter().any(|l| !l.has_name(sym::inline))).unwrap_or(false)
+ } else {
+ true
+ }
+}
+
fn should_encode_visibility(def_kind: DefKind) -> bool {
match def_kind {
DefKind::Mod
@@ -1120,14 +1093,44 @@ fn should_encode_const(def_kind: DefKind) -> bool {
}
}
+fn should_encode_trait_impl_trait_tys<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
+ if tcx.def_kind(def_id) != DefKind::AssocFn {
+ return false;
+ }
+
+ let Some(item) = tcx.opt_associated_item(def_id) else { return false; };
+ if item.container != ty::AssocItemContainer::ImplContainer {
+ return false;
+ }
+
+ let Some(trait_item_def_id) = item.trait_item_def_id else { return false; };
+
+ // FIXME(RPITIT): This does a somewhat manual walk through the signature
+ // of the trait fn to look for any RPITITs, but that's kinda doing a lot
+ // of work. We can probably remove this when we refactor RPITITs to be
+ // associated types.
+ tcx.fn_sig(trait_item_def_id).skip_binder().output().walk().any(|arg| {
+ if let ty::GenericArgKind::Type(ty) = arg.unpack()
+ && let ty::Projection(data) = ty.kind()
+ && tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder
+ {
+ true
+ } else {
+ false
+ }
+ })
+}
+
impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_attrs(&mut self, def_id: LocalDefId) {
- let mut attrs = self
- .tcx
+ let tcx = self.tcx;
+ let mut is_public: Option<bool> = None;
+
+ let mut attrs = tcx
.hir()
- .attrs(self.tcx.hir().local_def_id_to_hir_id(def_id))
+ .attrs(tcx.hir().local_def_id_to_hir_id(def_id))
.iter()
- .filter(|attr| !rustc_feature::is_builtin_only_local(attr.name_or_empty()));
+ .filter(move |attr| should_encode_attr(tcx, attr, def_id, &mut is_public));
record_array!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone());
if attrs.any(|attr| attr.may_have_doc_links()) {
@@ -1189,6 +1192,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
if let DefKind::Trait | DefKind::TraitAlias = def_kind {
record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id));
}
+ if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind {
+ let params_in_repr = self.tcx.params_in_repr(def_id);
+ record!(self.tables.params_in_repr[def_id] <- params_in_repr);
+ }
+ if should_encode_trait_impl_trait_tys(tcx, def_id)
+ && let Ok(table) = self.tcx.collect_trait_impl_trait_tys(def_id)
+ {
+ record!(self.tables.trait_impl_trait_tys[def_id] <- table);
+ }
}
let inherent_impls = tcx.crate_inherent_impls(());
for (def_id, implementations) in inherent_impls.inherent_impls.iter() {
@@ -1278,14 +1290,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
// from name resolution point of view.
hir::ItemKind::ForeignMod { items, .. } => {
for foreign_item in items {
- yield foreign_item.id.def_id.local_def_index;
+ yield foreign_item.id.owner_id.def_id.local_def_index;
}
}
// Only encode named non-reexport children, reexports are encoded
// separately and unnamed items are not used by name resolution.
hir::ItemKind::ExternCrate(..) => continue,
- _ if tcx.def_key(item_id.def_id.to_def_id()).get_opt_name().is_some() => {
- yield item_id.def_id.local_def_index;
+ hir::ItemKind::Struct(ref vdata, _) => {
+ yield item_id.owner_id.def_id.local_def_index;
+ // Encode constructors which take a separate slot in value namespace.
+ if let Some(ctor_hir_id) = vdata.ctor_hir_id() {
+ yield tcx.hir().local_def_id(ctor_hir_id).local_def_index;
+ }
+ }
+ _ if tcx.def_key(item_id.owner_id.to_def_id()).get_opt_name().is_some() => {
+ yield item_id.owner_id.def_id.local_def_index;
}
_ => continue,
}
@@ -1436,6 +1455,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
}
}
+
+ // Encode all the deduced parameter attributes for everything that has MIR, even for items
+ // that can't be inlined. But don't if we aren't optimizing in non-incremental mode, to
+ // save the query traffic.
+ if tcx.sess.opts.output_types.should_codegen()
+ && tcx.sess.opts.optimize != OptLevel::No
+ && tcx.sess.opts.incremental.is_none()
+ {
+ for &local_def_id in tcx.mir_keys(()) {
+ if let DefKind::AssocFn | DefKind::Fn = tcx.def_kind(local_def_id) {
+ record_array!(self.tables.deduced_param_attrs[local_def_id.to_def_id()] <-
+ self.tcx.deduced_param_attrs(local_def_id.to_def_id()));
+ }
+ }
+ }
}
fn encode_stability(&mut self, def_id: DefId) {
@@ -1507,7 +1541,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
record!(self.tables.macro_definition[def_id] <- &*macro_def.body);
}
hir::ItemKind::Mod(ref m) => {
- return self.encode_info_for_mod(item.def_id, m);
+ return self.encode_info_for_mod(item.owner_id.def_id, m);
}
hir::ItemKind::OpaqueTy(..) => {
self.encode_explicit_item_bounds(def_id);
@@ -1592,12 +1626,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
};
// FIXME(eddyb) there should be a nicer way to do this.
match item.kind {
- hir::ItemKind::Enum(..) => record_array!(self.tables.children[def_id] <-
- self.tcx.adt_def(def_id).variants().iter().map(|v| {
- assert!(v.def_id.is_local());
- v.def_id.index
- })
- ),
+ hir::ItemKind::Enum(..) => {
+ record_array!(self.tables.children[def_id] <- iter::from_generator(||
+ for variant in tcx.adt_def(def_id).variants() {
+ yield variant.def_id.index;
+ // Encode constructors which take a separate slot in value namespace.
+ if let Some(ctor_def_id) = variant.ctor_def_id {
+ yield ctor_def_id.index;
+ }
+ }
+ ))
+ }
hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
record_array!(self.tables.children[def_id] <-
self.tcx.adt_def(def_id).non_enum_variant().fields.iter().map(|f| {
@@ -1634,7 +1673,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
// normally in the visitor walk.
match item.kind {
hir::ItemKind::Enum(..) => {
- let def = self.tcx.adt_def(item.def_id.to_def_id());
+ let def = self.tcx.adt_def(item.owner_id.to_def_id());
for (i, variant) in def.variants().iter_enumerated() {
self.encode_enum_variant_info(def, i);
@@ -1644,7 +1683,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
}
hir::ItemKind::Struct(ref struct_def, _) => {
- let def = self.tcx.adt_def(item.def_id.to_def_id());
+ let def = self.tcx.adt_def(item.owner_id.to_def_id());
// If the struct has a constructor, encode it.
if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id);
@@ -1653,13 +1692,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
hir::ItemKind::Impl { .. } => {
for &trait_item_def_id in
- self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter()
+ self.tcx.associated_item_def_ids(item.owner_id.to_def_id()).iter()
{
self.encode_info_for_impl_item(trait_item_def_id);
}
}
hir::ItemKind::Trait(..) => {
- for &item_def_id in self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter()
+ for &item_def_id in
+ self.tcx.associated_item_def_ids(item.owner_id.to_def_id()).iter()
{
self.encode_info_for_trait_item(item_def_id);
}
@@ -1900,8 +1940,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
FxHashMap::default();
for id in tcx.hir().items() {
- if matches!(tcx.def_kind(id.def_id), DefKind::Impl) {
- if let Some(trait_ref) = tcx.impl_trait_ref(id.def_id.to_def_id()) {
+ if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
+ if let Some(trait_ref) = tcx.impl_trait_ref(id.owner_id) {
let simplified_self_ty = fast_reject::simplify_type(
self.tcx,
trait_ref.self_ty(),
@@ -1911,7 +1951,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fx_hash_map
.entry(trait_ref.def_id)
.or_default()
- .push((id.def_id.local_def_index, simplified_self_ty));
+ .push((id.owner_id.def_id.local_def_index, simplified_self_ty));
}
}
}
@@ -2052,12 +2092,12 @@ impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> {
intravisit::walk_item(self, item);
match item.kind {
hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {} // ignore these
- _ => self.encode_info_for_item(item.def_id.to_def_id(), item),
+ _ => self.encode_info_for_item(item.owner_id.to_def_id(), item),
}
}
fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem<'tcx>) {
intravisit::walk_foreign_item(self, ni);
- self.encode_info_for_foreign_item(ni.def_id.to_def_id(), ni);
+ self.encode_info_for_foreign_item(ni.owner_id.to_def_id(), ni);
}
fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
intravisit::walk_generics(self, generics);
@@ -2276,8 +2316,8 @@ pub fn provide(providers: &mut Providers) {
let mut traits = Vec::new();
for id in tcx.hir().items() {
- if matches!(tcx.def_kind(id.def_id), DefKind::Trait | DefKind::TraitAlias) {
- traits.push(id.def_id.to_def_id())
+ if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) {
+ traits.push(id.owner_id.to_def_id())
}
}
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 748b3afec..27dc8ff16 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -1,6 +1,7 @@
use crate::creader::CrateMetadataRef;
use decoder::Metadata;
use def_path_hash_map::DefPathHashMapRef;
+use rustc_data_structures::fx::FxHashMap;
use table::TableBuilder;
use rustc_ast as ast;
@@ -12,7 +13,8 @@ use rustc_hir::def::{CtorKind, DefKind};
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId};
use rustc_hir::definitions::DefKey;
use rustc_hir::lang_items;
-use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
+use rustc_index::bit_set::{BitSet, FiniteBitSet};
+use rustc_index::vec::IndexVec;
use rustc_middle::metadata::ModChild;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
@@ -21,7 +23,7 @@ use rustc_middle::mir;
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, ReprOptions, Ty};
-use rustc_middle::ty::{GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt};
+use rustc_middle::ty::{DeducedParamAttrs, GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt};
use rustc_serialize::opaque::FileEncoder;
use rustc_session::config::SymbolManglingVersion;
use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
@@ -382,6 +384,7 @@ define_tables! {
inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,
unused_generic_params: Table<DefIndex, LazyValue<FiniteBitSet<u32>>>,
+ params_in_repr: Table<DefIndex, LazyValue<BitSet<u32>>>,
repr_options: Table<DefIndex, LazyValue<ReprOptions>>,
// `def_keys` and `def_path_hashes` represent a lazy version of a
// `DefPathTable`. This allows us to avoid deserializing an entire
@@ -399,6 +402,9 @@ define_tables! {
macro_definition: Table<DefIndex, LazyValue<ast::MacArgs>>,
proc_macro: Table<DefIndex, MacroKind>,
module_reexports: Table<DefIndex, LazyArray<ModChild>>,
+ deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>,
+
+ trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, Ty<'static>>>>,
}
#[derive(TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index cca17a4ec..de916ea8c 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -12,8 +12,6 @@ chalk-ir = "0.80.0"
either = "1.5.0"
gsgdt = "0.1.2"
polonius-engine = "0.13.0"
-rand = "0.8.4"
-rand_xoshiro = "0.6.0"
rustc_apfloat = { path = "../rustc_apfloat" }
rustc_arena = { path = "../rustc_arena" }
rustc_ast = { path = "../rustc_ast" }
diff --git a/compiler/rustc_middle/benches/lib.rs b/compiler/rustc_middle/benches/lib.rs
deleted file mode 100644
index 237751bcb..000000000
--- a/compiler/rustc_middle/benches/lib.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-#![feature(test)]
-
-extern crate test;
-
-use test::Bencher;
-
-// Static/dynamic method dispatch
-
-struct Struct {
- field: isize,
-}
-
-trait Trait {
- fn method(&self) -> isize;
-}
-
-impl Trait for Struct {
- fn method(&self) -> isize {
- self.field
- }
-}
-
-#[bench]
-fn trait_vtable_method_call(b: &mut Bencher) {
- let s = Struct { field: 10 };
- let t = &s as &dyn Trait;
- b.iter(|| t.method());
-}
-
-#[bench]
-fn trait_static_method_call(b: &mut Bencher) {
- let s = Struct { field: 10 };
- b.iter(|| s.method());
-}
-
-// Overhead of various match forms
-
-#[bench]
-fn option_some(b: &mut Bencher) {
- let x = Some(10);
- b.iter(|| match x {
- Some(y) => y,
- None => 11,
- });
-}
-
-#[bench]
-fn vec_pattern(b: &mut Bencher) {
- let x = [1, 2, 3, 4, 5, 6];
- b.iter(|| match x {
- [1, 2, 3, ..] => 10,
- _ => 11,
- });
-}
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 6bdf5a023..f8aae86fe 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -77,7 +77,7 @@ macro_rules! arena_types {
rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Ty<'tcx>>
>,
[] all_traits: Vec<rustc_hir::def_id::DefId>,
- [] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels,
+ [] effective_visibilities: rustc_middle::middle::privacy::EffectiveVisibilities,
[] foreign_module: rustc_session::cstore::ForeignModule,
[] foreign_modules: Vec<rustc_session::cstore::ForeignModule>,
[] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>,
@@ -96,13 +96,14 @@ macro_rules! arena_types {
// since we need to allocate this type on both the `rustc_hir` arena
// (during lowering) and the `librustc_middle` arena (for decoding MIR)
[decode] asm_template: rustc_ast::InlineAsmTemplatePiece,
- [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>,
+ [decode] used_trait_imports: rustc_data_structures::unord::UnordSet<rustc_hir::def_id::LocalDefId>,
[decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::def_id::LocalDefId>,
[decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>,
[] 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>>,
+ [] bit_set_u32: rustc_index::bit_set::BitSet<u32>,
]);
)
}
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 1fa0c6bab..6b5568269 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -62,86 +62,13 @@ use crate::ty::TyCtxt;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
use rustc_hir::definitions::DefPathHash;
-use rustc_hir::HirId;
+use rustc_hir::{HirId, ItemLocalId, OwnerId};
use rustc_query_system::dep_graph::FingerprintStyle;
use rustc_span::symbol::Symbol;
use std::hash::Hash;
pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams};
-/// This struct stores metadata about each DepKind.
-///
-/// Information is retrieved by indexing the `DEP_KINDS` array using the integer value
-/// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual
-/// jump table instead of large matches.
-pub struct DepKindStruct<'tcx> {
- /// Anonymous queries cannot be replayed from one compiler invocation to the next.
- /// When their result is needed, it is recomputed. They are useful for fine-grained
- /// dependency tracking, and caching within one compiler invocation.
- pub is_anon: bool,
-
- /// Eval-always queries do not track their dependencies, and are always recomputed, even if
- /// their inputs have not changed since the last compiler invocation. The result is still
- /// cached within one compiler invocation.
- pub is_eval_always: bool,
-
- /// Whether the query key can be recovered from the hashed fingerprint.
- /// See [DepNodeParams] trait for the behaviour of each key type.
- pub fingerprint_style: FingerprintStyle,
-
- /// The red/green evaluation system will try to mark a specific DepNode in the
- /// dependency graph as green by recursively trying to mark the dependencies of
- /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
- /// where we don't know if it is red or green and we therefore actually have
- /// to recompute its value in order to find out. Since the only piece of
- /// information that we have at that point is the `DepNode` we are trying to
- /// re-evaluate, we need some way to re-run a query from just that. This is what
- /// `force_from_dep_node()` implements.
- ///
- /// In the general case, a `DepNode` consists of a `DepKind` and an opaque
- /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
- /// is usually constructed by computing a stable hash of the query-key that the
- /// `DepNode` corresponds to. Consequently, it is not in general possible to go
- /// back from hash to query-key (since hash functions are not reversible). For
- /// this reason `force_from_dep_node()` is expected to fail from time to time
- /// because we just cannot find out, from the `DepNode` alone, what the
- /// corresponding query-key is and therefore cannot re-run the query.
- ///
- /// The system deals with this case letting `try_mark_green` fail which forces
- /// the root query to be re-evaluated.
- ///
- /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
- /// Fortunately, we can use some contextual information that will allow us to
- /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
- /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
- /// valid `DefPathHash`. Since we also always build a huge table that maps every
- /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
- /// everything we need to re-run the query.
- ///
- /// Take the `mir_promoted` query as an example. Like many other queries, it
- /// just has a single parameter: the `DefId` of the item it will compute the
- /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
- /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
- /// is actually a `DefPathHash`, and can therefore just look up the corresponding
- /// `DefId` in `tcx.def_path_hash_to_def_id`.
- pub force_from_dep_node: Option<fn(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool>,
-
- /// Invoke a query to put the on-disk cached value in memory.
- pub try_load_from_on_disk_cache: Option<fn(TyCtxt<'tcx>, DepNode)>,
-}
-
-impl DepKind {
- #[inline(always)]
- pub fn fingerprint_style(self, tcx: TyCtxt<'_>) -> FingerprintStyle {
- // Only fetch the DepKindStruct once.
- let data = tcx.query_kind(self);
- if data.is_anon {
- return FingerprintStyle::Opaque;
- }
- data.fingerprint_style
- }
-}
-
macro_rules! define_dep_nodes {
(
$($(#[$attr:meta])*
@@ -159,7 +86,7 @@ macro_rules! define_dep_nodes {
$( $( #[$attr] )* $variant),*
}
- fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> {
+ pub(super) fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> {
match label {
$(stringify!($variant) => Ok(DepKind::$variant),)*
_ => Err(()),
@@ -214,11 +141,6 @@ static_assert_size!(DepNode, 18);
static_assert_size!(DepNode, 24);
pub trait DepNodeExt: Sized {
- /// Construct a DepNode from the given DepKind and DefPathHash. This
- /// method will assert that the given DepKind actually requires a
- /// single DefId/DefPathHash parameter.
- fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> Self;
-
/// Extracts the DefId corresponding to this DepNode. This will work
/// if two conditions are met:
///
@@ -243,14 +165,6 @@ pub trait DepNodeExt: Sized {
}
impl DepNodeExt for DepNode {
- /// Construct a DepNode from the given DepKind and DefPathHash. This
- /// method will assert that the given DepKind actually requires a
- /// single DefId/DefPathHash parameter.
- fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
- debug_assert!(kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash);
- DepNode { kind, hash: def_path_hash.0.into() }
- }
-
/// Extracts the DefId corresponding to this DepNode. This will work
/// if two conditions are met:
///
@@ -262,7 +176,7 @@ impl DepNodeExt for DepNode {
/// refers to something from the previous compilation session that
/// has been removed.
fn extract_def_id<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
- if self.kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash {
+ if tcx.fingerprint_style(self.kind) == FingerprintStyle::DefPathHash {
Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()), &mut || {
panic!("Failed to extract DefId: {:?} {}", self.kind, self.hash)
}))
@@ -279,8 +193,8 @@ impl DepNodeExt for DepNode {
) -> Result<DepNode, ()> {
let kind = dep_kind_from_label_string(label)?;
- match kind.fingerprint_style(tcx) {
- FingerprintStyle::Opaque => Err(()),
+ match tcx.fingerprint_style(kind) {
+ FingerprintStyle::Opaque | FingerprintStyle::HirId => Err(()),
FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
FingerprintStyle::DefPathHash => {
Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind))
@@ -355,6 +269,28 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId {
}
}
+impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for OwnerId {
+ #[inline(always)]
+ fn fingerprint_style() -> FingerprintStyle {
+ FingerprintStyle::DefPathHash
+ }
+
+ #[inline(always)]
+ fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
+ self.to_def_id().to_fingerprint(tcx)
+ }
+
+ #[inline(always)]
+ fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
+ self.to_def_id().to_debug_str(tcx)
+ }
+
+ #[inline(always)]
+ fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
+ dep_node.extract_def_id(tcx).map(|id| OwnerId { def_id: id.expect_local() })
+ }
+}
+
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
@@ -408,7 +344,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) {
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
- FingerprintStyle::Opaque
+ FingerprintStyle::HirId
}
// We actually would not need to specialize the implementation of this
@@ -417,10 +353,36 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId {
#[inline(always)]
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
let HirId { owner, local_id } = *self;
-
let def_path_hash = tcx.def_path_hash(owner.to_def_id());
- let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into());
+ Fingerprint::new(
+ // `owner` is local, so is completely defined by the local hash
+ def_path_hash.local_hash(),
+ local_id.as_u32().into(),
+ )
+ }
+
+ #[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())
+ }
- def_path_hash.0.combine(local_id)
+ #[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 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 || {
+ panic!("Failed to extract HirId: {:?} {}", dep_node.kind, dep_node.hash)
+ })
+ .expect_local();
+ let local_id = local_id
+ .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) })
+ } else {
+ None
+ }
}
}
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index c8b3b52b0..2e62bebc8 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -11,15 +11,17 @@ pub use rustc_query_system::dep_graph::{
SerializedDepNodeIndex, WorkProduct, WorkProductId,
};
-pub use dep_node::{label_strs, DepKind, DepKindStruct, DepNode, DepNodeExt};
+pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt};
pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item};
pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
+
pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
pub type TaskDepsRef<'a> = rustc_query_system::dep_graph::TaskDepsRef<'a, DepKind>;
pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>;
pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>;
pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>;
+pub type DepKindStruct<'tcx> = rustc_query_system::dep_graph::DepKindStruct<TyCtxt<'tcx>>;
impl rustc_query_system::dep_graph::DepKind for DepKind {
const NULL: Self = DepKind::Null;
@@ -91,50 +93,8 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
self.sess
}
- #[inline(always)]
- fn fingerprint_style(&self, kind: DepKind) -> rustc_query_system::dep_graph::FingerprintStyle {
- kind.fingerprint_style(*self)
- }
-
- #[inline(always)]
- fn is_eval_always(&self, kind: DepKind) -> bool {
- self.query_kind(kind).is_eval_always
- }
-
- fn try_force_from_dep_node(&self, dep_node: DepNode) -> bool {
- debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
-
- // We must avoid ever having to call `force_from_dep_node()` for a
- // `DepNode::codegen_unit`:
- // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
- // would always end up having to evaluate the first caller of the
- // `codegen_unit` query that *is* reconstructible. This might very well be
- // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
- // to re-trigger calling the `codegen_unit` query with the right key. At
- // that point we would already have re-done all the work we are trying to
- // avoid doing in the first place.
- // The solution is simple: Just explicitly call the `codegen_unit` query for
- // each CGU, right after partitioning. This way `try_mark_green` will always
- // hit the cache instead of having to go through `force_from_dep_node`.
- // This assertion makes sure, we actually keep applying the solution above.
- debug_assert!(
- dep_node.kind != DepKind::codegen_unit,
- "calling force_from_dep_node() on DepKind::codegen_unit"
- );
-
- let cb = self.query_kind(dep_node.kind);
- if let Some(f) = cb.force_from_dep_node {
- f(*self, dep_node);
- true
- } else {
- false
- }
- }
-
- fn try_load_from_on_disk_cache(&self, dep_node: DepNode) {
- let cb = self.query_kind(dep_node.kind);
- if let Some(f) = cb.try_load_from_on_disk_cache {
- f(*self, dep_node)
- }
+ #[inline]
+ fn dep_kind_info(&self, dep_kind: DepKind) -> &DepKindStruct<'tcx> {
+ &self.query_kinds[dep_kind as usize]
}
}
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index 18b31a75b..a7a7ac059 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -1,10 +1,10 @@
-use rustc_macros::SessionDiagnostic;
+use rustc_macros::Diagnostic;
use rustc_span::Span;
use crate::ty::Ty;
-#[derive(SessionDiagnostic)]
-#[diag(middle::drop_check_overflow, code = "E0320")]
+#[derive(Diagnostic)]
+#[diag(middle_drop_check_overflow, code = "E0320")]
#[note]
pub struct DropCheckOverflow<'tcx> {
#[primary_span]
@@ -13,8 +13,8 @@ pub struct DropCheckOverflow<'tcx> {
pub overflow_ty: Ty<'tcx>,
}
-#[derive(SessionDiagnostic)]
-#[diag(middle::opaque_hidden_type_mismatch)]
+#[derive(Diagnostic)]
+#[diag(middle_opaque_hidden_type_mismatch)]
pub struct OpaqueHiddenTypeMismatch<'tcx> {
pub self_ty: Ty<'tcx>,
pub other_ty: Ty<'tcx>,
@@ -25,22 +25,22 @@ pub struct OpaqueHiddenTypeMismatch<'tcx> {
pub sub: TypeMismatchReason,
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub enum TypeMismatchReason {
- #[label(middle::conflict_types)]
+ #[label(middle_conflict_types)]
ConflictType {
#[primary_span]
span: Span,
},
- #[note(middle::previous_use_here)]
+ #[note(middle_previous_use_here)]
PreviousUse {
#[primary_span]
span: Span,
},
}
-#[derive(SessionDiagnostic)]
-#[diag(middle::limit_invalid)]
+#[derive(Diagnostic)]
+#[diag(middle_limit_invalid)]
pub struct LimitInvalid<'a> {
#[primary_span]
pub span: Span,
@@ -48,3 +48,10 @@ pub struct LimitInvalid<'a> {
pub value_span: Span,
pub error_str: &'a str,
}
+
+#[derive(Diagnostic)]
+#[diag(middle_const_eval_non_int)]
+pub struct ConstEvalNonIntError {
+ #[primary_span]
+ pub span: Span,
+}
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 30a23c342..83a4d16d7 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -14,7 +14,7 @@ use rustc_index::vec::Idx;
use rustc_middle::hir::nested_filter;
use rustc_span::def_id::StableCrateId;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
#[inline]
@@ -61,7 +61,7 @@ pub struct ParentHirIterator<'hir> {
}
impl<'hir> Iterator for ParentHirIterator<'hir> {
- type Item = (HirId, Node<'hir>);
+ type Item = HirId;
fn next(&mut self) -> Option<Self::Item> {
if self.current_id == CRATE_HIR_ID {
@@ -77,10 +77,7 @@ impl<'hir> Iterator for ParentHirIterator<'hir> {
}
self.current_id = parent_id;
- if let Some(node) = self.map.find(parent_id) {
- return Some((parent_id, node));
- }
- // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
+ return Some(parent_id);
}
}
}
@@ -93,7 +90,7 @@ pub struct ParentOwnerIterator<'hir> {
}
impl<'hir> Iterator for ParentOwnerIterator<'hir> {
- type Item = (LocalDefId, OwnerNode<'hir>);
+ type Item = (OwnerId, OwnerNode<'hir>);
fn next(&mut self) -> Option<Self::Item> {
if self.current_id.local_id.index() != 0 {
@@ -107,13 +104,13 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> {
}
loop {
// There are nodes that do not have entries, so we need to skip them.
- let parent_id = self.map.def_key(self.current_id.owner).parent;
+ let parent_id = self.map.def_key(self.current_id.owner.def_id).parent;
- let parent_id = parent_id.map_or(CRATE_HIR_ID.owner, |local_def_index| {
+ let parent_id = parent_id.map_or(CRATE_OWNER_ID, |local_def_index| {
let def_id = LocalDefId { local_def_index };
self.map.local_def_id_to_hir_id(def_id).owner
});
- self.current_id = HirId::make_owner(parent_id);
+ self.current_id = HirId::make_owner(parent_id.def_id);
// If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) {
@@ -131,7 +128,7 @@ impl<'hir> Map<'hir> {
#[inline]
pub fn root_module(self) -> &'hir Mod<'hir> {
- match self.tcx.hir_owner(CRATE_DEF_ID).map(|o| o.node) {
+ match self.tcx.hir_owner(CRATE_OWNER_ID).map(|o| o.node) {
Some(OwnerNode::Crate(item)) => item,
_ => bug!(),
}
@@ -186,7 +183,7 @@ impl<'hir> Map<'hir> {
#[inline]
pub fn opt_local_def_id(self, hir_id: HirId) -> Option<LocalDefId> {
if hir_id.local_id == ItemLocalId::new(0) {
- Some(hir_id.owner)
+ Some(hir_id.owner.def_id)
} else {
self.tcx
.hir_owner_nodes(hir_id.owner)
@@ -244,7 +241,7 @@ impl<'hir> Map<'hir> {
Node::ImplItem(item) => match item.kind {
ImplItemKind::Const(..) => DefKind::AssocConst,
ImplItemKind::Fn(..) => DefKind::AssocFn,
- ImplItemKind::TyAlias(..) => DefKind::AssocTy,
+ ImplItemKind::Type(..) => DefKind::AssocTy,
},
Node::Variant(_) => DefKind::Variant,
Node::Ctor(variant_data) => {
@@ -352,24 +349,24 @@ impl<'hir> Map<'hir> {
}
pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
- let node = self.tcx.hir_owner(id)?;
+ let node = self.tcx.hir_owner(OwnerId { def_id: id })?;
node.node.generics()
}
pub fn item(self, id: ItemId) -> &'hir Item<'hir> {
- self.tcx.hir_owner(id.def_id).unwrap().node.expect_item()
+ self.tcx.hir_owner(id.owner_id).unwrap().node.expect_item()
}
pub fn trait_item(self, id: TraitItemId) -> &'hir TraitItem<'hir> {
- self.tcx.hir_owner(id.def_id).unwrap().node.expect_trait_item()
+ self.tcx.hir_owner(id.owner_id).unwrap().node.expect_trait_item()
}
pub fn impl_item(self, id: ImplItemId) -> &'hir ImplItem<'hir> {
- self.tcx.hir_owner(id.def_id).unwrap().node.expect_impl_item()
+ self.tcx.hir_owner(id.owner_id).unwrap().node.expect_impl_item()
}
pub fn foreign_item(self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
- self.tcx.hir_owner(id.def_id).unwrap().node.expect_foreign_item()
+ self.tcx.hir_owner(id.owner_id).unwrap().node.expect_foreign_item()
}
pub fn body(self, id: BodyId) -> &'hir Body<'hir> {
@@ -393,8 +390,8 @@ impl<'hir> Map<'hir> {
}
pub fn enclosing_body_owner(self, hir_id: HirId) -> LocalDefId {
- for (parent, _) in self.parent_iter(hir_id) {
- if let Some(body) = self.find(parent).map(associated_body).flatten() {
+ for (_, node) in self.parent_iter(hir_id) {
+ if let Some(body) = associated_body(node) {
return self.body_owner_def_id(body);
}
}
@@ -532,7 +529,7 @@ impl<'hir> Map<'hir> {
pub fn get_module(self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) {
let hir_id = HirId::make_owner(module);
- match self.tcx.hir_owner(module).map(|o| o.node) {
+ match self.tcx.hir_owner(hir_id.owner).map(|o| o.node) {
Some(OwnerNode::Item(&Item { span, kind: ItemKind::Mod(ref m), .. })) => {
(m, span, hir_id)
}
@@ -622,26 +619,33 @@ impl<'hir> Map<'hir> {
pub fn for_each_module(self, mut f: impl FnMut(LocalDefId)) {
let crate_items = self.tcx.hir_crate_items(());
for module in crate_items.submodules.iter() {
- f(*module)
+ f(module.def_id)
}
}
#[inline]
pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + Sync + Send) {
let crate_items = self.tcx.hir_crate_items(());
- par_for_each_in(&crate_items.submodules[..], |module| f(*module))
+ par_for_each_in(&crate_items.submodules[..], |module| f(module.def_id))
}
/// Returns an iterator for the nodes in the ancestor tree of the `current_id`
/// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
#[inline]
- pub fn parent_iter(self, current_id: HirId) -> ParentHirIterator<'hir> {
+ pub fn parent_id_iter(self, current_id: HirId) -> impl Iterator<Item = HirId> + 'hir {
ParentHirIterator { current_id, map: self }
}
/// Returns an iterator for the nodes in the ancestor tree of the `current_id`
/// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
#[inline]
+ pub fn parent_iter(self, current_id: HirId) -> impl Iterator<Item = (HirId, Node<'hir>)> {
+ self.parent_id_iter(current_id).filter_map(move |id| Some((id, self.find(id)?)))
+ }
+
+ /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
+ /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
+ #[inline]
pub fn parent_owner_iter(self, current_id: HirId) -> ParentOwnerIterator<'hir> {
ParentOwnerIterator { current_id, map: self }
}
@@ -721,27 +725,27 @@ impl<'hir> Map<'hir> {
None
}
- /// Retrieves the `HirId` for `id`'s parent item, or `id` itself if no
+ /// Retrieves the `OwnerId` for `id`'s parent item, or `id` itself if no
/// parent item is in this map. The "parent item" is the closest parent node
/// in the HIR which is recorded by the map and is an item, either an item
/// in a module, trait, or impl.
- pub fn get_parent_item(self, hir_id: HirId) -> LocalDefId {
+ pub fn get_parent_item(self, hir_id: HirId) -> OwnerId {
if let Some((def_id, _node)) = self.parent_owner_iter(hir_id).next() {
def_id
} else {
- CRATE_DEF_ID
+ CRATE_OWNER_ID
}
}
- /// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no
+ /// Returns the `OwnerId` of `id`'s nearest module parent, or `id` itself if no
/// module parent is in this map.
- pub(super) fn get_module_parent_node(self, hir_id: HirId) -> LocalDefId {
+ pub(super) fn get_module_parent_node(self, hir_id: HirId) -> OwnerId {
for (def_id, node) in self.parent_owner_iter(hir_id) {
if let OwnerNode::Item(&Item { kind: ItemKind::Mod(_), .. }) = node {
return def_id;
}
}
- CRATE_DEF_ID
+ CRATE_OWNER_ID
}
/// When on an if expression, a match arm tail expression or a match arm, give back
@@ -814,30 +818,30 @@ impl<'hir> Map<'hir> {
}
bug!(
"expected foreign mod or inlined parent, found {}",
- self.node_to_string(HirId::make_owner(parent))
+ self.node_to_string(HirId::make_owner(parent.def_id))
)
}
- pub fn expect_owner(self, id: LocalDefId) -> OwnerNode<'hir> {
+ pub fn expect_owner(self, id: OwnerId) -> OwnerNode<'hir> {
self.tcx.hir_owner(id).unwrap_or_else(|| bug!("expected owner for {:?}", id)).node
}
pub fn expect_item(self, id: LocalDefId) -> &'hir Item<'hir> {
- match self.tcx.hir_owner(id) {
+ match self.tcx.hir_owner(OwnerId { def_id: id }) {
Some(Owner { node: OwnerNode::Item(item), .. }) => item,
_ => bug!("expected item, found {}", self.node_to_string(HirId::make_owner(id))),
}
}
pub fn expect_impl_item(self, id: LocalDefId) -> &'hir ImplItem<'hir> {
- match self.tcx.hir_owner(id) {
+ match self.tcx.hir_owner(OwnerId { def_id: id }) {
Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item,
_ => bug!("expected impl item, found {}", self.node_to_string(HirId::make_owner(id))),
}
}
pub fn expect_trait_item(self, id: LocalDefId) -> &'hir TraitItem<'hir> {
- match self.tcx.hir_owner(id) {
+ match self.tcx.hir_owner(OwnerId { def_id: id }) {
Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item,
_ => bug!("expected trait item, found {}", self.node_to_string(HirId::make_owner(id))),
}
@@ -850,11 +854,14 @@ impl<'hir> Map<'hir> {
}
}
- pub fn expect_foreign_item(self, id: LocalDefId) -> &'hir ForeignItem<'hir> {
+ pub fn expect_foreign_item(self, id: OwnerId) -> &'hir ForeignItem<'hir> {
match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item,
_ => {
- bug!("expected foreign item, found {}", self.node_to_string(HirId::make_owner(id)))
+ bug!(
+ "expected foreign item, found {}",
+ self.node_to_string(HirId::make_owner(id.def_id))
+ )
}
}
}
@@ -934,9 +941,19 @@ impl<'hir> Map<'hir> {
let span = match self.find(hir_id)? {
// Function-like.
- Node::Item(Item { kind: ItemKind::Fn(sig, ..), .. })
- | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, ..), .. })
- | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, ..), .. }) => sig.span,
+ Node::Item(Item { kind: ItemKind::Fn(sig, ..), span: outer_span, .. })
+ | Node::TraitItem(TraitItem {
+ kind: TraitItemKind::Fn(sig, ..),
+ span: outer_span,
+ ..
+ })
+ | Node::ImplItem(ImplItem {
+ kind: ImplItemKind::Fn(sig, ..), span: outer_span, ..
+ }) => {
+ // Ensure that the returned span has the item's SyntaxContext, and not the
+ // SyntaxContext of the visibility.
+ sig.span.find_ancestor_in_same_ctxt(*outer_span).unwrap_or(*outer_span)
+ }
// Constants and Statics.
Node::Item(Item {
kind:
@@ -978,7 +995,11 @@ impl<'hir> Map<'hir> {
}
// Other cases.
Node::Item(item) => match &item.kind {
- ItemKind::Use(path, _) => path.span,
+ ItemKind::Use(path, _) => {
+ // Ensure that the returned span has the item's SyntaxContext, and not the
+ // SyntaxContext of the path.
+ path.span.find_ancestor_in_same_ctxt(item.span).unwrap_or(item.span)
+ }
_ => named_span(item.span, item.ident, item.kind.generics()),
},
Node::Variant(variant) => named_span(variant.span, variant.ident, None),
@@ -988,11 +1009,17 @@ impl<'hir> Map<'hir> {
_ => named_span(item.span, item.ident, None),
},
Node::Ctor(_) => return self.opt_span(self.get_parent_node(hir_id)),
- Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl_span, .. }), .. }) => {
- *fn_decl_span
+ Node::Expr(Expr {
+ kind: ExprKind::Closure(Closure { fn_decl_span, .. }),
+ span,
+ ..
+ }) => {
+ // Ensure that the returned span has the item's SyntaxContext.
+ fn_decl_span.find_ancestor_in_same_ctxt(*span).unwrap_or(*span)
}
_ => self.span_with_body(hir_id),
};
+ debug_assert_eq!(span.ctxt(), self.span_with_body(hir_id).ctxt());
Some(span)
}
@@ -1128,7 +1155,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
.filter_map(|(def_id, info)| {
let _ = info.as_owner()?;
let def_path_hash = definitions.def_path_hash(def_id);
- let span = resolutions.source_span[def_id];
+ let span = resolutions.source_span.get(def_id).unwrap_or(&DUMMY_SP);
debug_assert_eq!(span.parent(), None);
Some((def_path_hash, span))
})
@@ -1217,7 +1244,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
format!("assoc const {} in {}{}", ii.ident, path_str(), id_str)
}
ImplItemKind::Fn(..) => format!("method {} in {}{}", ii.ident, path_str(), id_str),
- ImplItemKind::TyAlias(_) => {
+ ImplItemKind::Type(_) => {
format!("assoc type {} in {}{}", ii.ident, path_str(), id_str)
}
},
@@ -1290,7 +1317,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
// A "crate collector" and "module collector" start at a
// module item (the former starts at the crate root) but only
// the former needs to collect it. ItemCollector does not do this for us.
- collector.submodules.push(CRATE_DEF_ID);
+ collector.submodules.push(CRATE_OWNER_ID);
tcx.hir().walk_toplevel_module(&mut collector);
let ItemCollector {
@@ -1318,7 +1345,7 @@ struct ItemCollector<'tcx> {
// otherwise it collects items in some module.
crate_collector: bool,
tcx: TyCtxt<'tcx>,
- submodules: Vec<LocalDefId>,
+ submodules: Vec<OwnerId>,
items: Vec<ItemId>,
trait_items: Vec<TraitItemId>,
impl_items: Vec<ImplItemId>,
@@ -1350,14 +1377,14 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
fn visit_item(&mut self, item: &'hir Item<'hir>) {
if associated_body(Node::Item(item)).is_some() {
- self.body_owners.push(item.def_id);
+ self.body_owners.push(item.owner_id.def_id);
}
self.items.push(item.item_id());
// Items that are modules are handled here instead of in visit_mod.
if let ItemKind::Mod(module) = &item.kind {
- self.submodules.push(item.def_id);
+ self.submodules.push(item.owner_id);
// A module collector does not recurse inside nested modules.
if self.crate_collector {
intravisit::walk_mod(self, module, item.hir_id());
@@ -1386,7 +1413,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) {
if associated_body(Node::TraitItem(item)).is_some() {
- self.body_owners.push(item.def_id);
+ self.body_owners.push(item.owner_id.def_id);
}
self.trait_items.push(item.trait_item_id());
@@ -1395,7 +1422,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) {
if associated_body(Node::ImplItem(item)).is_some() {
- self.body_owners.push(item.def_id);
+ self.body_owners.push(item.owner_id.def_id);
}
self.impl_items.push(item.impl_item_id());
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 211a61471..1c6264ad0 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -39,7 +39,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> {
/// bodies. The Ids are in visitor order. This is used to partition a pass between modules.
#[derive(Debug, HashStable, Encodable, Decodable)]
pub struct ModuleItems {
- submodules: Box<[LocalDefId]>,
+ submodules: Box<[OwnerId]>,
items: Box<[ItemId]>,
trait_items: Box<[TraitItemId]>,
impl_items: Box<[ImplItemId]>,
@@ -67,10 +67,10 @@ impl ModuleItems {
pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ {
self.items
.iter()
- .map(|id| id.def_id)
- .chain(self.trait_items.iter().map(|id| id.def_id))
- .chain(self.impl_items.iter().map(|id| id.def_id))
- .chain(self.foreign_items.iter().map(|id| id.def_id))
+ .map(|id| id.owner_id.def_id)
+ .chain(self.trait_items.iter().map(|id| id.owner_id.def_id))
+ .chain(self.impl_items.iter().map(|id| id.owner_id.def_id))
+ .chain(self.foreign_items.iter().map(|id| id.owner_id.def_id))
}
pub fn par_items(&self, f: impl Fn(ItemId) + Send + Sync) {
@@ -97,7 +97,7 @@ impl<'tcx> TyCtxt<'tcx> {
}
pub fn parent_module(self, id: HirId) -> LocalDefId {
- self.parent_module_from_def_id(id.owner)
+ self.parent_module_from_def_id(id.owner.def_id)
}
pub fn impl_subject(self, def_id: DefId) -> ImplSubject<'tcx> {
@@ -110,13 +110,13 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn provide(providers: &mut Providers) {
providers.parent_module_from_def_id = |tcx, id| {
let hir = tcx.hir();
- hir.get_module_parent_node(hir.local_def_id_to_hir_id(id))
+ hir.get_module_parent_node(hir.local_def_id_to_hir_id(id)).def_id
};
providers.hir_crate_items = map::hir_crate_items;
providers.crate_hash = map::crate_hash;
providers.hir_module_items = map::hir_module_items;
providers.hir_owner = |tcx, id| {
- let owner = tcx.hir_crate(()).owners.get(id)?.as_owner()?;
+ let owner = tcx.hir_crate(()).owners.get(id.def_id)?.as_owner()?;
let node = owner.node();
Some(Owner { node, hash_without_bodies: owner.nodes.hash_without_bodies })
};
@@ -128,21 +128,24 @@ pub fn provide(providers: &mut Providers) {
MaybeOwner::NonOwner(hir_id) => hir_id,
}
};
- providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id].map(|i| &i.nodes);
+ providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id.def_id].map(|i| &i.nodes);
providers.hir_owner_parent = |tcx, id| {
// Accessing the local_parent is ok since its value is hashed as part of `id`'s DefPathHash.
- tcx.opt_local_parent(id).map_or(CRATE_HIR_ID, |parent| {
+ tcx.opt_local_parent(id.def_id).map_or(CRATE_HIR_ID, |parent| {
let mut parent_hir_id = tcx.hir().local_def_id_to_hir_id(parent);
- if let Some(local_id) =
- tcx.hir_crate(()).owners[parent_hir_id.owner].unwrap().parenting.get(&id)
+ if let Some(local_id) = tcx.hir_crate(()).owners[parent_hir_id.owner.def_id]
+ .unwrap()
+ .parenting
+ .get(&id.def_id)
{
parent_hir_id.local_id = *local_id;
}
parent_hir_id
})
};
- providers.hir_attrs =
- |tcx, id| tcx.hir_crate(()).owners[id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs);
+ providers.hir_attrs = |tcx, id| {
+ tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
+ };
providers.source_span =
|tcx, def_id| tcx.resolutions(()).source_span.get(def_id).copied().unwrap_or(DUMMY_SP);
providers.def_span = |tcx, def_id| {
@@ -177,6 +180,7 @@ pub fn provide(providers: &mut Providers) {
let id = id.expect_local();
tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root())
};
- providers.in_scope_traits_map =
- |tcx, id| tcx.hir_crate(()).owners[id].as_owner().map(|owner_info| &owner_info.trait_map);
+ providers.in_scope_traits_map = |tcx, id| {
+ tcx.hir_crate(()).owners[id.def_id].as_owner().map(|owner_info| &owner_info.trait_map)
+ };
}
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index f2627885d..41d8c7ffd 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -129,7 +129,7 @@ impl<'tcx> UnifyKey for ty::ConstVid<'tcx> {
}
impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
- type Error = (ty::Const<'tcx>, ty::Const<'tcx>);
+ type Error = NoError;
fn unify_values(&value1: &Self, &value2: &Self) -> Result<Self, Self::Error> {
Ok(match (value1.val, value2.val) {
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 01b9277b9..a58cbc376 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -31,22 +31,19 @@
#![feature(discriminant_kind)]
#![feature(exhaustive_patterns)]
#![feature(get_mut_unchecked)]
-#![cfg_attr(bootstrap, feature(generic_associated_types))]
#![feature(if_let_guard)]
-#![feature(map_first_last)]
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(extern_types)]
#![feature(new_uninit)]
#![feature(once_cell)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(min_specialization)]
#![feature(trusted_len)]
#![feature(type_alias_impl_trait)]
#![feature(associated_type_bounds)]
#![feature(rustc_attrs)]
-#![feature(half_open_range_patterns)]
+#![cfg_attr(bootstrap, feature(half_open_range_patterns))]
#![feature(control_flow_enum)]
#![feature(associated_type_defaults)]
#![feature(trusted_step)]
@@ -58,6 +55,7 @@
#![feature(drain_filter)]
#![feature(intra_doc_pointers)]
#![feature(yeet_expr)]
+#![feature(result_option_inspect)]
#![feature(const_option)]
#![recursion_limit = "512"]
#![allow(rustc::potential_query_instability)]
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 2f45222de..79522bd0b 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -1,20 +1,20 @@
use std::cmp;
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_errors::{Diagnostic, DiagnosticId, LintDiagnosticBuilder, MultiSpan};
-use rustc_hir::HirId;
-use rustc_index::vec::IndexVec;
-use rustc_query_system::ich::StableHashingContext;
+use rustc_data_structures::sorted_map::SortedMap;
+use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, MultiSpan};
+use rustc_hir::{HirId, ItemLocalId};
use rustc_session::lint::{
builtin::{self, FORBIDDEN_LINT_GROUPS},
- FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId,
+ FutureIncompatibilityReason, Level, Lint, LintId,
};
use rustc_session::Session;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::{DesugaringKind, ExpnKind};
use rustc_span::{symbol, Span, Symbol, DUMMY_SP};
+use crate::ty::TyCtxt;
+
/// How a lint level was set.
#[derive(Clone, Copy, PartialEq, Eq, HashStable, Debug)]
pub enum LintLevelSource {
@@ -23,7 +23,12 @@ pub enum LintLevelSource {
Default,
/// Lint level was set by an attribute.
- Node(Symbol, Span, Option<Symbol> /* RFC 2383 reason */),
+ Node {
+ name: Symbol,
+ span: Span,
+ /// RFC 2383 reason
+ reason: Option<Symbol>,
+ },
/// Lint level was set by a command-line flag.
/// The provided `Level` is the level specified on the command line.
@@ -35,7 +40,7 @@ impl LintLevelSource {
pub fn name(&self) -> Symbol {
match *self {
LintLevelSource::Default => symbol::kw::Default,
- LintLevelSource::Node(name, _, _) => name,
+ LintLevelSource::Node { name, .. } => name,
LintLevelSource::CommandLine(name, _) => name,
}
}
@@ -43,7 +48,7 @@ impl LintLevelSource {
pub fn span(&self) -> Span {
match *self {
LintLevelSource::Default => DUMMY_SP,
- LintLevelSource::Node(_, span, _) => span,
+ LintLevelSource::Node { span, .. } => span,
LintLevelSource::CommandLine(_, _) => DUMMY_SP,
}
}
@@ -52,145 +57,137 @@ impl LintLevelSource {
/// A tuple of a lint level and its source.
pub type LevelAndSource = (Level, LintLevelSource);
-#[derive(Debug, HashStable)]
-pub struct LintLevelSets {
- pub list: IndexVec<LintStackIndex, LintSet>,
- pub lint_cap: Level,
-}
-
-rustc_index::newtype_index! {
- #[derive(HashStable)]
- pub struct LintStackIndex {
- const COMMAND_LINE = 0,
- }
-}
-
-#[derive(Debug, HashStable)]
-pub struct LintSet {
- // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
- // flag.
- pub specs: FxHashMap<LintId, LevelAndSource>,
-
- pub parent: LintStackIndex,
+/// Return type for the `shallow_lint_levels_on` query.
+///
+/// This map represents the set of allowed lints and allowance levels given
+/// by the attributes for *a single HirId*.
+#[derive(Default, Debug, HashStable)]
+pub struct ShallowLintLevelMap {
+ pub specs: SortedMap<ItemLocalId, FxHashMap<LintId, LevelAndSource>>,
}
-impl LintLevelSets {
- pub fn new() -> Self {
- LintLevelSets { list: IndexVec::new(), lint_cap: Level::Forbid }
- }
-
- pub fn get_lint_level(
- &self,
- lint: &'static Lint,
- idx: LintStackIndex,
- aux: Option<&FxHashMap<LintId, LevelAndSource>>,
- sess: &Session,
- ) -> LevelAndSource {
- let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
-
- // If `level` is none then we actually assume the default level for this
- // lint.
- let mut level = level.unwrap_or_else(|| lint.default_level(sess.edition()));
-
- // If we're about to issue a warning, check at the last minute for any
- // directives against the warnings "lint". If, for example, there's an
- // `allow(warnings)` in scope then we want to respect that instead.
- //
- // We exempt `FORBIDDEN_LINT_GROUPS` from this because it specifically
- // triggers in cases (like #80988) where you have `forbid(warnings)`,
- // and so if we turned that into an error, it'd defeat the purpose of the
- // future compatibility warning.
- if level == Level::Warn && LintId::of(lint) != LintId::of(FORBIDDEN_LINT_GROUPS) {
- let (warnings_level, warnings_src) =
- self.get_lint_id_level(LintId::of(builtin::WARNINGS), idx, aux);
- if let Some(configured_warning_level) = warnings_level {
- if configured_warning_level != Level::Warn {
- level = configured_warning_level;
- src = warnings_src;
- }
+/// From an initial level and source, verify the effect of special annotations:
+/// `warnings` lint level and lint caps.
+///
+/// The return of this function is suitable for diagnostics.
+pub fn reveal_actual_level(
+ level: Option<Level>,
+ src: &mut LintLevelSource,
+ sess: &Session,
+ lint: LintId,
+ probe_for_lint_level: impl FnOnce(LintId) -> (Option<Level>, LintLevelSource),
+) -> Level {
+ // If `level` is none then we actually assume the default level for this lint.
+ let mut level = level.unwrap_or_else(|| lint.lint.default_level(sess.edition()));
+
+ // If we're about to issue a warning, check at the last minute for any
+ // directives against the warnings "lint". If, for example, there's an
+ // `allow(warnings)` in scope then we want to respect that instead.
+ //
+ // We exempt `FORBIDDEN_LINT_GROUPS` from this because it specifically
+ // triggers in cases (like #80988) where you have `forbid(warnings)`,
+ // and so if we turned that into an error, it'd defeat the purpose of the
+ // future compatibility warning.
+ if level == Level::Warn && lint != LintId::of(FORBIDDEN_LINT_GROUPS) {
+ let (warnings_level, warnings_src) = probe_for_lint_level(LintId::of(builtin::WARNINGS));
+ if let Some(configured_warning_level) = warnings_level {
+ if configured_warning_level != Level::Warn {
+ level = configured_warning_level;
+ *src = warnings_src;
}
}
+ }
- // Ensure that we never exceed the `--cap-lints` argument
- // unless the source is a --force-warn
- level = if let LintLevelSource::CommandLine(_, Level::ForceWarn(_)) = src {
- level
- } else {
- cmp::min(level, self.lint_cap)
- };
-
- if let Some(driver_level) = sess.driver_lint_caps.get(&LintId::of(lint)) {
- // Ensure that we never exceed driver level.
- level = cmp::min(*driver_level, level);
- }
+ // Ensure that we never exceed the `--cap-lints` argument unless the source is a --force-warn
+ level = if let LintLevelSource::CommandLine(_, Level::ForceWarn(_)) = src {
+ level
+ } else {
+ cmp::min(level, sess.opts.lint_cap.unwrap_or(Level::Forbid))
+ };
- (level, src)
+ if let Some(driver_level) = sess.driver_lint_caps.get(&lint) {
+ // Ensure that we never exceed driver level.
+ level = cmp::min(*driver_level, level);
}
- pub fn get_lint_id_level(
+ level
+}
+
+impl ShallowLintLevelMap {
+ /// Perform a deep probe in the HIR tree looking for the actual level for the lint.
+ /// This lint level is not usable for diagnostics, it needs to be corrected by
+ /// `reveal_actual_level` beforehand.
+ #[instrument(level = "trace", skip(self, tcx), ret)]
+ fn probe_for_lint_level(
&self,
+ tcx: TyCtxt<'_>,
id: LintId,
- mut idx: LintStackIndex,
- aux: Option<&FxHashMap<LintId, LevelAndSource>>,
+ start: HirId,
) -> (Option<Level>, LintLevelSource) {
- if let Some(specs) = aux {
- if let Some(&(level, src)) = specs.get(&id) {
- return (Some(level), src);
- }
+ if let Some(map) = self.specs.get(&start.local_id)
+ && let Some(&(level, src)) = map.get(&id)
+ {
+ return (Some(level), src);
}
- loop {
- let LintSet { ref specs, parent } = self.list[idx];
- if let Some(&(level, src)) = specs.get(&id) {
- return (Some(level), src);
+
+ let mut owner = start.owner;
+ let mut specs = &self.specs;
+
+ for parent in tcx.hir().parent_id_iter(start) {
+ if parent.owner != owner {
+ owner = parent.owner;
+ specs = &tcx.shallow_lint_levels_on(owner).specs;
}
- if idx == COMMAND_LINE {
- return (None, LintLevelSource::Default);
+ if let Some(map) = specs.get(&parent.local_id)
+ && let Some(&(level, src)) = map.get(&id)
+ {
+ return (Some(level), src);
}
- idx = parent;
}
- }
-}
-#[derive(Debug)]
-pub struct LintLevelMap {
- /// This is a collection of lint expectations as described in RFC 2383, that
- /// can be fulfilled during this compilation session. This means that at least
- /// one expected lint is currently registered in the lint store.
- ///
- /// The [`LintExpectationId`] is stored as a part of the [`Expect`](Level::Expect)
- /// lint level.
- pub lint_expectations: Vec<(LintExpectationId, LintExpectation)>,
- pub sets: LintLevelSets,
- pub id_to_set: FxHashMap<HirId, LintStackIndex>,
-}
+ (None, LintLevelSource::Default)
+ }
-impl LintLevelMap {
- /// If the `id` was previously registered with `register_id` when building
- /// this `LintLevelMap` this returns the corresponding lint level and source
- /// of the lint level for the lint provided.
- ///
- /// If the `id` was not previously registered, returns `None`. If `None` is
- /// returned then the parent of `id` should be acquired and this function
- /// should be called again.
- pub fn level_and_source(
+ /// Fetch and return the user-visible lint level for the given lint at the given HirId.
+ #[instrument(level = "trace", skip(self, tcx), ret)]
+ pub fn lint_level_id_at_node(
&self,
- lint: &'static Lint,
- id: HirId,
- session: &Session,
- ) -> Option<LevelAndSource> {
- self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session))
+ tcx: TyCtxt<'_>,
+ lint: LintId,
+ cur: HirId,
+ ) -> (Level, LintLevelSource) {
+ let (level, mut src) = self.probe_for_lint_level(tcx, lint, cur);
+ let level = reveal_actual_level(level, &mut src, tcx.sess, lint, |lint| {
+ self.probe_for_lint_level(tcx, lint, cur)
+ });
+ (level, src)
}
}
-impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
- #[inline]
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- let LintLevelMap { ref sets, ref id_to_set, ref lint_expectations } = *self;
+impl TyCtxt<'_> {
+ /// Fetch and return the user-visible lint level for the given lint at the given HirId.
+ pub fn lint_level_at_node(self, lint: &'static Lint, id: HirId) -> (Level, LintLevelSource) {
+ self.shallow_lint_levels_on(id.owner).lint_level_id_at_node(self, LintId::of(lint), id)
+ }
- id_to_set.hash_stable(hcx, hasher);
- lint_expectations.hash_stable(hcx, hasher);
+ /// Walks upwards from `id` to find a node which might change lint levels with attributes.
+ /// It stops at `bound` and just returns it if reached.
+ pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId {
+ let hir = self.hir();
+ loop {
+ if id == bound {
+ return bound;
+ }
- hcx.while_hashing_spans(true, |hcx| sets.hash_stable(hcx, hasher))
+ if hir.attrs(id).iter().any(|attr| Level::from_attr(attr).is_some()) {
+ return id;
+ }
+ let next = hir.get_parent_node(id);
+ if next == id {
+ bug!("lint traversal reached the root of the crate");
+ }
+ id = next;
+ }
}
}
@@ -261,11 +258,11 @@ pub fn explain_lint_level_source(
));
}
}
- LintLevelSource::Node(lint_attr_name, src, reason) => {
+ LintLevelSource::Node { name: lint_attr_name, span, reason, .. } => {
if let Some(rationale) = reason {
err.note(rationale.as_str());
}
- err.span_note_once(src, "the lint level is defined here");
+ 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!(
@@ -277,23 +274,65 @@ pub fn explain_lint_level_source(
}
}
-pub fn struct_lint_level<'s, 'd>(
- sess: &'s Session,
+/// The innermost function for emitting lints.
+///
+/// If you are loocking to implement a lint, look for higher level functions,
+/// for example:
+/// - [`TyCtxt::emit_spanned_lint`]
+/// - [`TyCtxt::struct_span_lint_hir`]
+/// - [`TyCtxt::emit_lint`]
+/// - [`TyCtxt::struct_lint_node`]
+/// - `LintContext::lookup`
+///
+/// ## `decorate` signature
+///
+/// The return value of `decorate` is ignored by this function. So what is the
+/// point of returning `&'b mut DiagnosticBuilder<'a, ()>`?
+///
+/// There are 2 reasons for this signature.
+///
+/// First of all, it prevents accidental use of `.emit()` -- it's clear that the
+/// builder will be later used and shouldn't be emitted right away (this is
+/// especially important because the old API expected you to call `.emit()` in
+/// the closure).
+///
+/// Second of all, it makes the most common case of adding just a single label
+/// /suggestion much nicer, since [`DiagnosticBuilder`] methods return
+/// `&mut DiagnosticBuilder`, you can just chain methods, without needed
+/// awkward `{ ...; }`:
+/// ```ignore pseudo-code
+/// struct_lint_level(
+/// ...,
+/// |lint| lint.span_label(sp, "lbl")
+/// // ^^^^^^^^^^^^^^^^^^^^^ returns `&mut DiagnosticBuilder` by default
+/// )
+/// ```
+pub fn struct_lint_level(
+ sess: &Session,
lint: &'static Lint,
level: Level,
src: LintLevelSource,
span: Option<MultiSpan>,
- decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>) + 'd,
+ msg: impl Into<DiagnosticMessage>,
+ decorate: impl for<'a, 'b> FnOnce(
+ &'b mut DiagnosticBuilder<'a, ()>,
+ ) -> &'b mut DiagnosticBuilder<'a, ()>,
) {
// Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to
// the "real" work.
- fn struct_lint_level_impl<'s, 'd>(
- sess: &'s Session,
+ fn struct_lint_level_impl(
+ sess: &Session,
lint: &'static Lint,
level: Level,
src: LintLevelSource,
span: Option<MultiSpan>,
- decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b, ()>) + 'd>,
+ msg: impl Into<DiagnosticMessage>,
+ decorate: Box<
+ dyn '_
+ + for<'a, 'b> FnOnce(
+ &'b mut DiagnosticBuilder<'a, ()>,
+ ) -> &'b mut DiagnosticBuilder<'a, ()>,
+ >,
) {
// Check for future incompatibility lints and issue a stronger warning.
let future_incompatible = lint.future_incompatible;
@@ -344,6 +383,8 @@ pub fn struct_lint_level<'s, 'd>(
(Level::Deny | Level::Forbid, None) => sess.diagnostic().struct_err_lint(""),
};
+ err.set_is_lint();
+
// If this code originates in a foreign macro, aka something that this crate
// did not itself author, then it's likely that there's nothing this crate
// can do about it. We probably want to skip the lint entirely.
@@ -366,6 +407,10 @@ pub fn struct_lint_level<'s, 'd>(
}
}
+ // Delay evaluating and setting the primary message until after we've
+ // suppressed the lint due to macros.
+ err.set_primary_message(msg);
+
// Lint diagnostics that are covered by the expect level will not be emitted outside
// the compiler. It is therefore not necessary to add any information for the user.
// This will therefore directly call the decorate function which will in turn emit
@@ -373,12 +418,12 @@ pub fn struct_lint_level<'s, 'd>(
if let Level::Expect(_) = level {
let name = lint.name_lower();
err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn: false });
- decorate(LintDiagnosticBuilder::new(err));
+
+ decorate(&mut err);
+ err.emit();
return;
}
- explain_lint_level_source(lint, level, src, &mut err);
-
let name = lint.name_lower();
let is_force_warn = matches!(level, Level::ForceWarn(_));
err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn });
@@ -417,10 +462,12 @@ pub fn struct_lint_level<'s, 'd>(
}
}
- // Finally, run `decorate`. This function is also responsible for emitting the diagnostic.
- decorate(LintDiagnosticBuilder::new(err));
+ // Finally, run `decorate`.
+ decorate(&mut err);
+ explain_lint_level_source(lint, level, src, &mut *err);
+ err.emit()
}
- struct_lint_level_impl(sess, lint, level, src, span, Box::new(decorate))
+ struct_lint_level_impl(sess, lint, level, src, span, msg, Box::new(decorate))
}
/// Returns whether `span` originates in a foreign crate's external macro.
@@ -432,7 +479,9 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool {
match expn_data.kind {
ExpnKind::Inlined
| ExpnKind::Root
- | ExpnKind::Desugaring(DesugaringKind::ForLoop | DesugaringKind::WhileLoop) => false,
+ | ExpnKind::Desugaring(
+ DesugaringKind::ForLoop | DesugaringKind::WhileLoop | DesugaringKind::OpaqueTy,
+ ) => false,
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
ExpnKind::Macro(MacroKind::Bang, _) => {
// Dummy span for the `def_site` means it's an external macro.
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index 0e85c60a3..01fe72de6 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -54,13 +54,22 @@ macro_rules! TrivialTypeTraversalImpls {
impl<$tcx> $crate::ty::fold::TypeFoldable<$tcx> for $ty {
fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$tcx>>(
self,
- _: &mut F
- ) -> ::std::result::Result<$ty, F::Error> {
+ _: &mut F,
+ ) -> ::std::result::Result<Self, F::Error> {
Ok(self)
}
+
+ #[inline]
+ fn fold_with<F: $crate::ty::fold::TypeFolder<$tcx>>(
+ self,
+ _: &mut F,
+ ) -> Self {
+ self
+ }
}
impl<$tcx> $crate::ty::visit::TypeVisitable<$tcx> for $ty {
+ #[inline]
fn visit_with<F: $crate::ty::visit::TypeVisitor<$tcx>>(
&self,
_: &mut F)
diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs
index 53c4d9267..12aef66bc 100644
--- a/compiler/rustc_middle/src/middle/limits.rs
+++ b/compiler/rustc_middle/src/middle/limits.rs
@@ -38,7 +38,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
tcx.hir().krate_attrs(),
tcx.sess,
sym::const_eval_limit,
- 1_000_000,
+ 2_000_000,
),
}
}
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index 751c7f464..9c68c7504 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -1,64 +1,218 @@
//! A pass that checks to make sure private fields and methods aren't used
//! outside their scopes. This pass will also generate a set of exported items
//! which are available for use externally when compiled as a library.
-
+use crate::ty::{DefIdTree, Visibility};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_macros::HashStable;
use rustc_query_system::ich::StableHashingContext;
-use rustc_span::def_id::LocalDefId;
+use rustc_span::def_id::{DefId, LocalDefId};
use std::hash::Hash;
-/// Represents the levels of accessibility an item can have.
+/// Represents the levels of effective visibility an item can have.
///
-/// The variants are sorted in ascending order of accessibility.
+/// The variants are sorted in ascending order of directness.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, HashStable)]
-pub enum AccessLevel {
- /// Superset of `AccessLevel::Reachable` used to mark impl Trait items.
- ReachableFromImplTrait,
- /// Exported items + items participating in various kinds of public interfaces,
- /// but not directly nameable. For example, if function `fn f() -> T {...}` is
- /// public, then type `T` is reachable. Its values can be obtained by other crates
- /// even if the type itself is not nameable.
+pub enum Level {
+ /// Superset of `Reachable` including items leaked through return position `impl Trait`.
+ ReachableThroughImplTrait,
+ /// Item is either reexported, or leaked through any kind of interface.
+ /// For example, if function `fn f() -> T {...}` is directly public, then type `T` is publicly
+ /// reachable and its values can be obtained by other crates even if the type itself is not
+ /// nameable.
Reachable,
- /// Public items + items accessible to other crates with the help of `pub use` re-exports.
- Exported,
- /// Items accessible to other crates directly, without the help of re-exports.
- Public,
+ /// Item is accessible either directly, or with help of `use` reexports.
+ Reexported,
+ /// Item is directly accessible, without help of reexports.
+ Direct,
+}
+
+impl Level {
+ pub fn all_levels() -> [Level; 4] {
+ [Level::Direct, Level::Reexported, Level::Reachable, Level::ReachableThroughImplTrait]
+ }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
+pub struct EffectiveVisibility {
+ direct: Visibility,
+ reexported: Visibility,
+ reachable: Visibility,
+ reachable_through_impl_trait: Visibility,
+}
+
+impl EffectiveVisibility {
+ pub fn at_level(&self, level: Level) -> &Visibility {
+ match level {
+ Level::Direct => &self.direct,
+ Level::Reexported => &self.reexported,
+ Level::Reachable => &self.reachable,
+ Level::ReachableThroughImplTrait => &self.reachable_through_impl_trait,
+ }
+ }
+
+ fn at_level_mut(&mut self, level: Level) -> &mut Visibility {
+ match level {
+ Level::Direct => &mut self.direct,
+ Level::Reexported => &mut self.reexported,
+ Level::Reachable => &mut self.reachable,
+ Level::ReachableThroughImplTrait => &mut self.reachable_through_impl_trait,
+ }
+ }
+
+ pub fn is_public_at_level(&self, level: Level) -> bool {
+ self.at_level(level).is_public()
+ }
+
+ pub fn from_vis(vis: Visibility) -> EffectiveVisibility {
+ EffectiveVisibility {
+ direct: vis,
+ reexported: vis,
+ reachable: vis,
+ reachable_through_impl_trait: vis,
+ }
+ }
}
-/// Holds a map of accessibility levels for reachable HIR nodes.
+/// Holds a map of effective visibilities for reachable HIR nodes.
#[derive(Debug, Clone)]
-pub struct AccessLevels<Id = LocalDefId> {
- pub map: FxHashMap<Id, AccessLevel>,
+pub struct EffectiveVisibilities<Id = LocalDefId> {
+ map: FxHashMap<Id, EffectiveVisibility>,
}
-impl<Id: Hash + Eq> AccessLevels<Id> {
- /// See `AccessLevel::Reachable`.
+impl<Id: Hash + Eq + Copy> EffectiveVisibilities<Id> {
+ pub fn is_public_at_level(&self, id: Id, level: Level) -> bool {
+ self.effective_vis(id)
+ .map_or(false, |effective_vis| effective_vis.is_public_at_level(level))
+ }
+
+ /// See `Level::Reachable`.
pub fn is_reachable(&self, id: Id) -> bool {
- self.map.get(&id) >= Some(&AccessLevel::Reachable)
+ self.is_public_at_level(id, Level::Reachable)
}
- /// See `AccessLevel::Exported`.
+ /// See `Level::Reexported`.
pub fn is_exported(&self, id: Id) -> bool {
- self.map.get(&id) >= Some(&AccessLevel::Exported)
+ self.is_public_at_level(id, Level::Reexported)
+ }
+
+ /// See `Level::Direct`.
+ pub fn is_directly_public(&self, id: Id) -> bool {
+ self.is_public_at_level(id, Level::Direct)
+ }
+
+ pub fn public_at_level(&self, id: Id) -> Option<Level> {
+ self.effective_vis(id).and_then(|effective_vis| {
+ for level in Level::all_levels() {
+ if effective_vis.is_public_at_level(level) {
+ return Some(level);
+ }
+ }
+ None
+ })
+ }
+
+ pub fn effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> {
+ self.map.get(&id)
}
- /// See `AccessLevel::Public`.
- pub fn is_public(&self, id: Id) -> bool {
- self.map.get(&id) >= Some(&AccessLevel::Public)
+ pub fn iter(&self) -> impl Iterator<Item = (&Id, &EffectiveVisibility)> {
+ self.map.iter()
+ }
+
+ pub fn map_id<OutId: Hash + Eq + Copy>(
+ &self,
+ f: impl Fn(Id) -> OutId,
+ ) -> EffectiveVisibilities<OutId> {
+ EffectiveVisibilities { map: self.map.iter().map(|(k, v)| (f(*k), *v)).collect() }
+ }
+
+ pub fn set_public_at_level(
+ &mut self,
+ id: Id,
+ default_vis: impl FnOnce() -> Visibility,
+ level: Level,
+ ) {
+ let mut effective_vis = self
+ .effective_vis(id)
+ .copied()
+ .unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis()));
+ for l in Level::all_levels() {
+ if l <= level {
+ *effective_vis.at_level_mut(l) = Visibility::Public;
+ }
+ }
+ self.map.insert(id, effective_vis);
+ }
+}
+
+impl<Id: Hash + Eq + Copy + Into<DefId>> EffectiveVisibilities<Id> {
+ // `parent_id` is not necessarily a parent in source code tree,
+ // it is the node from which the maximum effective visibility is inherited.
+ pub fn update(
+ &mut self,
+ id: Id,
+ nominal_vis: Visibility,
+ default_vis: impl FnOnce() -> Visibility,
+ parent_id: Id,
+ level: Level,
+ tree: impl DefIdTree,
+ ) -> bool {
+ let mut changed = false;
+ let mut current_effective_vis = self.effective_vis(id).copied().unwrap_or_else(|| {
+ if id.into().is_crate_root() {
+ EffectiveVisibility::from_vis(Visibility::Public)
+ } else {
+ EffectiveVisibility::from_vis(default_vis())
+ }
+ });
+ if let Some(inherited_effective_vis) = self.effective_vis(parent_id) {
+ let mut inherited_effective_vis_at_prev_level =
+ *inherited_effective_vis.at_level(level);
+ let mut calculated_effective_vis = inherited_effective_vis_at_prev_level;
+ for l in Level::all_levels() {
+ if level >= l {
+ let inherited_effective_vis_at_level = *inherited_effective_vis.at_level(l);
+ let current_effective_vis_at_level = current_effective_vis.at_level_mut(l);
+ // effective visibility for id shouldn't be recalculated if
+ // inherited from parent_id effective visibility isn't changed at next level
+ 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, tree) {
+ inherited_effective_vis_at_level
+ } else {
+ nominal_vis
+ };
+ }
+ // effective visibility can't be decreased at next update call for the
+ // same id
+ if *current_effective_vis_at_level != calculated_effective_vis
+ && calculated_effective_vis
+ .is_at_least(*current_effective_vis_at_level, tree)
+ {
+ changed = true;
+ *current_effective_vis_at_level = calculated_effective_vis;
+ }
+ inherited_effective_vis_at_prev_level = inherited_effective_vis_at_level;
+ }
+ }
+ }
+ self.map.insert(id, current_effective_vis);
+ changed
}
}
-impl<Id> Default for AccessLevels<Id> {
+impl<Id> Default for EffectiveVisibilities<Id> {
fn default() -> Self {
- AccessLevels { map: Default::default() }
+ EffectiveVisibilities { map: Default::default() }
}
}
-impl<'a> HashStable<StableHashingContext<'a>> for AccessLevels {
+impl<'a> HashStable<StableHashingContext<'a>> for EffectiveVisibilities {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- let AccessLevels { ref map } = *self;
+ let EffectiveVisibilities { ref map } = *self;
map.hash_stable(hcx, hasher);
}
}
diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
index a171f5711..c3bf1c717 100644
--- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs
+++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
@@ -2,9 +2,9 @@
use crate::ty;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::ItemLocalId;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def_id::DefId;
+use rustc_hir::{ItemLocalId, OwnerId};
use rustc_macros::HashStable;
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
@@ -49,12 +49,7 @@ pub enum ObjectLifetimeDefault {
pub struct ResolveLifetimes {
/// Maps from every use of a named (not anonymous) lifetime to a
/// `Region` describing how that region is bound
- pub defs: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Region>>,
+ pub defs: FxHashMap<OwnerId, FxHashMap<ItemLocalId, Region>>,
- /// Set of lifetime def ids that are late-bound; a region can
- /// be late-bound if (a) it does NOT appear in a where-clause and
- /// (b) it DOES appear in the arguments.
- pub late_bound: FxHashMap<LocalDefId, FxHashSet<LocalDefId>>,
-
- pub late_bound_vars: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>>,
+ pub late_bound_vars: FxHashMap<OwnerId, FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>>,
}
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index d182929c4..61bc089e4 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -253,13 +253,12 @@ fn late_report_deprecation(
return;
}
let method_span = method_span.unwrap_or(span);
- tcx.struct_span_lint_hir(lint, hir_id, method_span, |lint| {
- let mut diag = lint.build(message);
+ tcx.struct_span_lint_hir(lint, hir_id, method_span, message, |diag| {
if let hir::Node::Expr(_) = tcx.hir().get(hir_id) {
let kind = tcx.def_kind(def_id).descr(def_id);
- deprecation_suggestion(&mut diag, kind, suggestion, method_span);
+ deprecation_suggestion(diag, kind, suggestion, method_span);
}
- diag.emit();
+ diag
});
}
@@ -621,9 +620,7 @@ impl<'tcx> TyCtxt<'tcx> {
unmarked: impl FnOnce(Span, DefId),
) -> bool {
let soft_handler = |lint, span, msg: &_| {
- self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| {
- lint.build(msg).emit();
- })
+ self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, msg, |lint| lint)
};
let eval_result =
self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable);
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index e4039cc7c..b5a50cc15 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -479,12 +479,7 @@ impl<T: Any> AsAny for T {
}
/// A trait for machine-specific errors (or other "machine stop" conditions).
-pub trait MachineStopType: AsAny + fmt::Display + Send {
- /// If `true`, emit a hard error instead of going through the `CONST_ERR` lint
- fn is_hard_err(&self) -> bool {
- false
- }
-}
+pub trait MachineStopType: AsAny + fmt::Display + Send {}
impl dyn MachineStopType {
#[inline(always)]
@@ -543,16 +538,4 @@ impl InterpError<'_> {
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
)
}
-
- /// Should this error be reported as a hard error, preventing compilation, or a soft error,
- /// causing a deny-by-default lint?
- pub fn is_hard_err(&self) -> bool {
- use InterpError::*;
- match *self {
- MachineStop(ref err) => err.is_hard_err(),
- UndefinedBehavior(_) => true,
- ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted) => true,
- _ => false,
- }
- }
}
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
index 95e52e391..23c2ce647 100644
--- a/compiler/rustc_middle/src/mir/interpret/pointer.rs
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -43,7 +43,7 @@ pub trait PointerArithmetic: HasDataLayout {
let val = val as i64;
// Now wrap-around into the machine_isize range.
if val > self.machine_isize_max() {
- // This can only happen the the ptr size is < 64, so we know max_usize_plus_1 fits into
+ // This can only happen if the ptr size is < 64, so we know max_usize_plus_1 fits into
// i64.
debug_assert!(self.pointer_size().bits() < 64);
let max_usize_plus_1 = 1u128 << self.pointer_size().bits();
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index 4207988d7..473894ac1 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -4,7 +4,9 @@ use crate::mir;
use crate::ty::subst::InternalSubsts;
use crate::ty::visit::TypeVisitable;
use crate::ty::{self, query::TyCtxtAt, query::TyCtxtEnsure, TyCtxt};
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
+use rustc_session::lint;
use rustc_span::{Span, DUMMY_SP};
impl<'tcx> TyCtxt<'tcx> {
@@ -36,7 +38,7 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn const_eval_resolve(
self,
param_env: ty::ParamEnv<'tcx>,
- ct: ty::Unevaluated<'tcx>,
+ ct: mir::UnevaluatedConst<'tcx>,
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
// Cannot resolve `Unevaluated` constants that contain inference
@@ -45,11 +47,15 @@ impl<'tcx> TyCtxt<'tcx> {
//
// When trying to evaluate constants containing inference variables,
// use `Infcx::const_eval_resolve` instead.
- if ct.substs.has_infer_types_or_consts() {
+ if ct.substs.has_non_region_infer() {
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_opt_const_arg(
+ self, param_env,
+ // FIXME: maybe have a separate version for resolving mir::UnevaluatedConst?
+ ct.def, ct.substs,
+ ) {
Ok(Some(instance)) => {
let cid = GlobalId { instance, promoted: ct.promoted };
self.const_eval_global_id(param_env, cid, span)
@@ -63,7 +69,7 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn const_eval_resolve_for_typeck(
self,
param_env: ty::ParamEnv<'tcx>,
- ct: ty::Unevaluated<'tcx, ()>,
+ ct: ty::UnevaluatedConst<'tcx>,
span: Option<Span>,
) -> EvalToValTreeResult<'tcx> {
// Cannot resolve `Unevaluated` constants that contain inference
@@ -72,14 +78,36 @@ impl<'tcx> TyCtxt<'tcx> {
//
// When trying to evaluate constants containing inference variables,
// use `Infcx::const_eval_resolve` instead.
- if ct.substs.has_infer_types_or_consts() {
+ if ct.substs.has_non_region_infer() {
bug!("did not expect inference variables here");
}
match ty::Instance::resolve_opt_const_arg(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)
+ self.const_eval_global_id_for_typeck(param_env, cid, span).inspect(|_| {
+ // We are emitting the lint here instead of in `is_const_evaluatable`
+ // as we normalize obligations before checking them, and normalization
+ // uses this function to evaluate this constant.
+ //
+ // @lcnr believes that successfully evaluating even though there are
+ // 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);
+ if mir_body.is_polymorphic {
+ let Some(local_def_id) = ct.def.did.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),
+ "cannot use constants which depend on generic parameters in types",
+ |err| err,
+ )
+ }
+ }
+ })
}
Ok(None) => Err(ErrorHandled::TooGeneric),
Err(error_reported) => Err(ErrorHandled::Reported(error_reported)),
@@ -211,7 +239,7 @@ impl<'tcx> TyCtxt<'tcx> {
self,
param_env: ty::ParamEnv<'tcx>,
constant: mir::ConstantKind<'tcx>,
- ) -> mir::DestructuredMirConstant<'tcx> {
+ ) -> mir::DestructuredConstant<'tcx> {
self.try_destructure_mir_constant(param_env.and(constant)).unwrap()
}
}
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 3d7a6230e..79db35a76 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -7,12 +7,12 @@ use crate::mir::interpret::{
};
use crate::mir::visit::MirVisitable;
use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
use crate::ty::print::{FmtPrinter, Printer};
-use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
-use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use crate::ty::visit::{TypeVisitable, TypeVisitor};
use crate::ty::{self, List, Ty, TyCtxt};
use crate::ty::{AdtDef, InstanceDef, ScalarInt, UserTypeAnnotationIndex};
+use crate::ty::{GenericArg, InternalSubsts, SubstsRef};
use rustc_data_structures::captures::Captures;
use rustc_errors::ErrorGuaranteed;
@@ -116,11 +116,6 @@ pub trait MirPass<'tcx> {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
- /// If this pass causes the MIR to enter a new phase, return that phase.
- fn phase_change(&self) -> Option<MirPhase> {
- None
- }
-
fn is_mir_dump_enabled(&self) -> bool {
true
}
@@ -145,6 +140,35 @@ impl MirPhase {
}
}
+impl Display for MirPhase {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ match self {
+ MirPhase::Built => write!(f, "built"),
+ MirPhase::Analysis(p) => write!(f, "analysis-{}", p),
+ MirPhase::Runtime(p) => write!(f, "runtime-{}", p),
+ }
+ }
+}
+
+impl Display for AnalysisPhase {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ match self {
+ AnalysisPhase::Initial => write!(f, "initial"),
+ AnalysisPhase::PostCleanup => write!(f, "post_cleanup"),
+ }
+ }
+}
+
+impl Display for RuntimePhase {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ match self {
+ RuntimePhase::Initial => write!(f, "initial"),
+ RuntimePhase::PostCleanup => write!(f, "post_cleanup"),
+ RuntimePhase::Optimized => write!(f, "optimized"),
+ }
+ }
+}
+
/// Where a specific `mir::Body` comes from.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
@@ -207,6 +231,9 @@ pub struct Body<'tcx> {
/// us to see the difference and forego optimization on the inlined promoted items.
pub phase: MirPhase,
+ /// How many passses we have executed since starting the current phase. Used for debug output.
+ pub pass_count: usize,
+
pub source: MirSource<'tcx>,
/// A list of source scopes; these are referenced by statements
@@ -292,6 +319,7 @@ impl<'tcx> Body<'tcx> {
let mut body = Body {
phase: MirPhase::Built,
+ pass_count: 1,
source,
basic_blocks: BasicBlocks::new(basic_blocks),
source_scopes,
@@ -313,7 +341,7 @@ impl<'tcx> Body<'tcx> {
is_polymorphic: false,
tainted_by_errors,
};
- body.is_polymorphic = body.has_param_types_or_consts();
+ body.is_polymorphic = body.has_non_region_param();
body
}
@@ -325,6 +353,7 @@ impl<'tcx> Body<'tcx> {
pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
let mut body = Body {
phase: MirPhase::Built,
+ pass_count: 1,
source: MirSource::item(CRATE_DEF_ID.to_def_id()),
basic_blocks: BasicBlocks::new(basic_blocks),
source_scopes: IndexVec::new(),
@@ -339,7 +368,7 @@ impl<'tcx> Body<'tcx> {
is_polymorphic: false,
tainted_by_errors: None,
};
- body.is_polymorphic = body.has_param_types_or_consts();
+ body.is_polymorphic = body.has_non_region_param();
body
}
@@ -1380,6 +1409,7 @@ impl<V, T> ProjectionElem<V, T> {
Self::Field(_, _)
| Self::Index(_)
+ | Self::OpaqueCast(_)
| Self::ConstantIndex { .. }
| Self::Subslice { .. }
| Self::Downcast(_, _) => false,
@@ -1574,7 +1604,9 @@ impl Debug for Place<'_> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
for elem in self.projection.iter().rev() {
match elem {
- ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => {
+ ProjectionElem::OpaqueCast(_)
+ | ProjectionElem::Downcast(_, _)
+ | ProjectionElem::Field(_, _) => {
write!(fmt, "(").unwrap();
}
ProjectionElem::Deref => {
@@ -1590,6 +1622,9 @@ impl Debug for Place<'_> {
for elem in self.projection.iter() {
match elem {
+ ProjectionElem::OpaqueCast(ty) => {
+ write!(fmt, " as {})", ty)?;
+ }
ProjectionElem::Downcast(Some(name), _index) => {
write!(fmt, " as {})", name)?;
}
@@ -1818,7 +1853,6 @@ impl<'tcx> Rvalue<'tcx> {
// While the model is undecided, we should be conservative. See
// <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
- Rvalue::Cast(CastKind::DynStar, _, _) => false,
Rvalue::Use(_)
| Rvalue::CopyForDeref(_)
@@ -1828,7 +1862,15 @@ impl<'tcx> Rvalue<'tcx> {
| Rvalue::AddressOf(_, _)
| Rvalue::Len(_)
| Rvalue::Cast(
- CastKind::Misc | CastKind::Pointer(_) | CastKind::PointerFromExposedAddress,
+ CastKind::IntToInt
+ | CastKind::FloatToInt
+ | CastKind::FloatToFloat
+ | CastKind::IntToFloat
+ | CastKind::FnPtrToPtr
+ | CastKind::PtrToPtr
+ | CastKind::Pointer(_)
+ | CastKind::PointerFromExposedAddress
+ | CastKind::DynStar,
_,
_,
)
@@ -2043,13 +2085,13 @@ pub struct Constant<'tcx> {
}
#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
-#[derive(Lift)]
+#[derive(Lift, TypeFoldable, TypeVisitable)]
pub enum ConstantKind<'tcx> {
/// This constant came from the type system
Ty(ty::Const<'tcx>),
/// An unevaluated mir constant which is not part of the type system.
- Unevaluated(ty::Unevaluated<'tcx, Option<Promoted>>, Ty<'tcx>),
+ Unevaluated(UnevaluatedConst<'tcx>, Ty<'tcx>),
/// This constant cannot go back into the type system, as it represents
/// something the type system cannot handle (e.g. pointers).
@@ -2309,12 +2351,11 @@ impl<'tcx> ConstantKind<'tcx> {
ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty })
.substs;
- let uneval = ty::Unevaluated {
+ let uneval = UnevaluatedConst {
def: ty::WithOptConstParam::unknown(def_id).to_global(),
substs,
promoted: None,
};
-
debug_assert!(!uneval.has_free_regions());
Self::Unevaluated(uneval, ty)
@@ -2398,7 +2439,7 @@ impl<'tcx> ConstantKind<'tcx> {
let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
let span = tcx.hir().span(hir_id);
- let uneval = ty::Unevaluated::new(def.to_global(), substs);
+ let uneval = UnevaluatedConst::new(def.to_global(), substs);
debug!(?span, ?param_env);
match tcx.const_eval_resolve(param_env, uneval, Some(span)) {
@@ -2411,7 +2452,7 @@ impl<'tcx> ConstantKind<'tcx> {
// Error was handled in `const_eval_resolve`. Here we just create a
// new unevaluated const and error hard later in codegen
Self::Unevaluated(
- ty::Unevaluated {
+ UnevaluatedConst {
def: def.to_global(),
substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
promoted: None,
@@ -2434,6 +2475,34 @@ impl<'tcx> ConstantKind<'tcx> {
}
}
+/// An unevaluated (potentially generic) constant used in MIR.
+#[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 substs: SubstsRef<'tcx>,
+ pub promoted: Option<Promoted>,
+}
+
+impl<'tcx> UnevaluatedConst<'tcx> {
+ // FIXME: probably should get rid of this method. It's also wrong to
+ // shrink and then later expand a promoted.
+ #[inline]
+ pub fn shrink(self) -> ty::UnevaluatedConst<'tcx> {
+ ty::UnevaluatedConst { def: self.def, substs: self.substs }
+ }
+}
+
+impl<'tcx> UnevaluatedConst<'tcx> {
+ #[inline]
+ pub fn new(
+ def: ty::WithOptConstParam<DefId>,
+ substs: SubstsRef<'tcx>,
+ ) -> UnevaluatedConst<'tcx> {
+ UnevaluatedConst { def, substs, promoted: Default::default() }
+ }
+}
+
/// A collection of projections into user types.
///
/// They are projections because a binding can occur a part of a
@@ -2727,7 +2796,7 @@ fn pretty_print_const_value<'tcx>(
}
// Aggregates, printed as array/tuple/struct/variant construction syntax.
//
- // NB: the `has_param_types_or_consts` check ensures that we can use
+ // NB: the `has_non_region_param` check ensures that we can use
// the `destructure_const` query with an empty `ty::ParamEnv` without
// introducing ICEs (e.g. via `layout_of`) from missing bounds.
// E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized`
@@ -2735,7 +2804,7 @@ fn pretty_print_const_value<'tcx>(
//
// FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the
// correct `ty::ParamEnv` to allow printing *all* constant values.
- (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => {
+ (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_non_region_param() => {
let ct = tcx.lift(ct).unwrap();
let ty = tcx.lift(ty).unwrap();
if let Some(contents) = tcx.try_destructure_mir_constant(
@@ -2906,11 +2975,12 @@ impl Location {
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;
- // These are in alphabetical order, which is easy to maintain.
+ // tidy-alphabetical-start
static_assert_size!(BasicBlockData<'_>, 144);
static_assert_size!(LocalDecl<'_>, 56);
static_assert_size!(Statement<'_>, 32);
static_assert_size!(StatementKind<'_>, 16);
static_assert_size!(Terminator<'_>, 112);
static_assert_size!(TerminatorKind<'_>, 96);
+ // tidy-alphabetical-end
}
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 21ae121e1..15a24aa4a 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -81,7 +81,7 @@ impl<'tcx> MonoItem<'tcx> {
MonoItem::Fn(instance) => tcx.symbol_name(instance),
MonoItem::Static(def_id) => tcx.symbol_name(Instance::mono(tcx, def_id)),
MonoItem::GlobalAsm(item_id) => {
- SymbolName::new(tcx, &format!("global_asm_{:?}", item_id.def_id))
+ SymbolName::new(tcx, &format!("global_asm_{:?}", item_id.owner_id))
}
}
}
@@ -182,7 +182,7 @@ impl<'tcx> MonoItem<'tcx> {
match *self {
MonoItem::Fn(Instance { def, .. }) => def.def_id().as_local(),
MonoItem::Static(def_id) => def_id.as_local(),
- MonoItem::GlobalAsm(item_id) => Some(item_id.def_id),
+ MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.def_id),
}
.map(|def_id| tcx.def_span(def_id))
}
@@ -373,7 +373,7 @@ impl<'tcx> CodegenUnit<'tcx> {
}
}
MonoItem::Static(def_id) => def_id.as_local().map(Idx::index),
- MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.index()),
+ MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.def_id.index()),
},
item.symbol_name(tcx),
)
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 0b42137d4..05dcfba77 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -466,10 +466,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
ty::ConstKind::Param(p) => format!("Param({})", p),
ty::ConstKind::Unevaluated(uv) => {
format!(
- "Unevaluated({}, {:?}, {:?})",
+ "Unevaluated({}, {:?})",
self.tcx.def_path_str(uv.def.did),
uv.substs,
- uv.promoted,
)
}
ty::ConstKind::Value(val) => format!("Value({})", fmt_valtree(&val)),
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index d89efe2b3..efd7357af 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -392,16 +392,9 @@ pub enum ClosureOutlivesSubject<'tcx> {
Region(ty::RegionVid),
}
-/// The constituent parts of a type level constant of kind ADT or array.
-#[derive(Copy, Clone, Debug, HashStable)]
-pub struct DestructuredConst<'tcx> {
- pub variant: Option<VariantIdx>,
- pub fields: &'tcx [ty::Const<'tcx>],
-}
-
/// The constituent parts of a mir constant of kind ADT or array.
#[derive(Copy, Clone, Debug, HashStable)]
-pub struct DestructuredMirConstant<'tcx> {
+pub struct DestructuredConstant<'tcx> {
pub variant: Option<VariantIdx>,
pub fields: &'tcx [ConstantKind<'tcx>],
}
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index c7d0283aa..85ef51f12 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -82,9 +82,10 @@ pub enum MirPhase {
/// access to. This occurs in generator bodies. Such locals do not behave like other locals,
/// because they eg may be aliased in surprising ways. Runtime MIR has no such special locals -
/// all generator bodies are lowered and so all places that look like locals really are locals.
- /// - Const prop lints: The lint pass which reports eg `200_u8 + 200_u8` as an error is run as a
- /// part of analysis to runtime MIR lowering. This means that transformations which may supress
- /// such errors may not run on analysis MIR.
+ ///
+ /// Also note that the lint pass which reports eg `200_u8 + 200_u8` as an error is run as a part
+ /// of analysis to runtime MIR lowering. To ensure lints are reported reliably, this means that
+ /// transformations which may supress such errors should not run on analysis MIR.
Runtime(RuntimePhase),
}
@@ -829,6 +830,9 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
/// generator has more than one variant, the parent place's variant index must be set, indicating
/// which variant is being used. If it has just one variant, the variant index may or may not be
/// included - the single possible variant is inferred if it is not included.
+/// - [`OpaqueCast`](ProjectionElem::OpaqueCast): This projection changes the place's type to the
+/// given one, and makes no other changes. A `OpaqueCast` projection on any type other than an
+/// opaque type from the current crate is not well-formed.
/// - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the
/// place as described in the documentation for the `ProjectionElem`. The resulting address is
/// the parent's address plus that offset, and the type is `T`. This is only legal if the parent
@@ -928,6 +932,10 @@ pub enum ProjectionElem<V, T> {
///
/// The included Symbol is the name of the variant, used for printing MIR.
Downcast(Option<Symbol>, VariantIdx),
+
+ /// Like an explicit cast from an opaque type to a concrete type, but without
+ /// requiring an intermediate variable.
+ OpaqueCast(T),
}
/// Alias for projections as they appear in places, where the base is a place
@@ -1141,8 +1149,12 @@ pub enum CastKind {
Pointer(PointerCast),
/// Cast into a dyn* object.
DynStar,
- /// Remaining unclassified casts.
- Misc,
+ IntToInt,
+ FloatToInt,
+ FloatToFloat,
+ IntToFloat,
+ PtrToPtr,
+ FnPtrToPtr,
}
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
@@ -1233,11 +1245,11 @@ pub enum BinOp {
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
mod size_asserts {
use super::*;
- // These are in alphabetical order, which is easy to maintain.
- #[cfg(not(bootstrap))]
+ // tidy-alphabetical-start
static_assert_size!(AggregateKind<'_>, 40);
static_assert_size!(Operand<'_>, 24);
static_assert_size!(Place<'_>, 16);
static_assert_size!(PlaceElem<'_>, 24);
static_assert_size!(Rvalue<'_>, 40);
+ // tidy-alphabetical-end
}
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 405003156..fa3adafd4 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -4,7 +4,6 @@
*/
use crate::mir::*;
-use crate::ty::subst::Subst;
use crate::ty::{self, Ty, TyCtxt};
use rustc_hir as hir;
use rustc_target::abi::VariantIdx;
@@ -57,7 +56,7 @@ impl<'tcx> PlaceTy<'tcx> {
/// `PlaceElem`, where we can just use the `Ty` that is already
/// stored inline on field projection elems.
pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
- self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty)
+ self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty, |_, ty| ty)
}
/// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
@@ -71,6 +70,7 @@ impl<'tcx> PlaceTy<'tcx> {
param_env: ty::ParamEnv<'tcx>,
elem: &ProjectionElem<V, T>,
mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>,
+ mut handle_opaque_cast: impl FnMut(&Self, T) -> Ty<'tcx>,
) -> PlaceTy<'tcx>
where
V: ::std::fmt::Debug,
@@ -109,6 +109,7 @@ impl<'tcx> PlaceTy<'tcx> {
PlaceTy { ty: self.ty, variant_index: Some(index) }
}
ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
+ ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast(&self, ty)),
};
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
answer
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index 9d098c808..4c0974f86 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -26,6 +26,12 @@ TrivialTypeTraversalAndLiftImpls! {
GeneratorSavedLocal,
}
+TrivialTypeTraversalImpls! {
+ for <'tcx> {
+ ConstValue<'tcx>,
+ }
+}
+
impl<'tcx> TypeFoldable<'tcx> for &'tcx [InlineAsmTemplatePiece] {
fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
Ok(self)
@@ -49,25 +55,3 @@ impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
Ok(self)
}
}
-
-impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
- #[inline(always)]
- fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
- folder.try_fold_mir_const(self)
- }
-}
-
-impl<'tcx> TypeSuperFoldable<'tcx> for ConstantKind<'tcx> {
- fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
- self,
- folder: &mut F,
- ) -> Result<Self, F::Error> {
- match self {
- ConstantKind::Ty(c) => Ok(ConstantKind::Ty(c.try_fold_with(folder)?)),
- ConstantKind::Val(v, t) => Ok(ConstantKind::Val(v, t.try_fold_with(folder)?)),
- ConstantKind::Unevaluated(uv, t) => {
- Ok(ConstantKind::Unevaluated(uv.try_fold_with(folder)?, t.try_fold_with(folder)?))
- }
- }
- }
-}
diff --git a/compiler/rustc_middle/src/mir/type_visitable.rs b/compiler/rustc_middle/src/mir/type_visitable.rs
index be19bb486..e7cd497b2 100644
--- a/compiler/rustc_middle/src/mir/type_visitable.rs
+++ b/compiler/rustc_middle/src/mir/type_visitable.rs
@@ -7,22 +7,3 @@ impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix<R, C> {
ControlFlow::CONTINUE
}
}
-
-impl<'tcx> TypeVisitable<'tcx> for ConstantKind<'tcx> {
- fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
- visitor.visit_mir_const(*self)
- }
-}
-
-impl<'tcx> TypeSuperVisitable<'tcx> for ConstantKind<'tcx> {
- fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
- match *self {
- ConstantKind::Ty(c) => c.visit_with(visitor),
- ConstantKind::Val(_, t) => t.visit_with(visitor),
- ConstantKind::Unevaluated(uv, t) => {
- uv.visit_with(visitor)?;
- t.visit_with(visitor)
- }
- }
- }
-}
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index d9b24566b..ddcf3711b 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -1084,6 +1084,11 @@ macro_rules! visit_place_fns {
self.visit_ty(&mut new_ty, TyContext::Location(location));
if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
}
+ PlaceElem::OpaqueCast(ty) => {
+ let mut new_ty = ty;
+ self.visit_ty(&mut new_ty, TyContext::Location(location));
+ if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
+ }
PlaceElem::Deref
| PlaceElem::ConstantIndex { .. }
| PlaceElem::Subslice { .. }
@@ -1153,7 +1158,7 @@ macro_rules! visit_place_fns {
location: Location,
) {
match elem {
- ProjectionElem::Field(_field, ty) => {
+ ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => {
self.visit_ty(ty, TyContext::Location(location));
}
ProjectionElem::Index(local) => {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 4b336ea62..3d720f09b 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -4,6 +4,9 @@
//! ["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};
+use rustc_span::def_id::LOCAL_CRATE;
+
// Each of these queries corresponds to a function pointer field in the
// `Providers` struct for requesting a value of that type, and a method
// on `tcx: TyCtxt` (and `tcx.at(span)`) for doing that request in a way
@@ -17,19 +20,19 @@
// as they will raise an fatal error on query cycles instead.
rustc_queries! {
query trigger_delay_span_bug(key: DefId) -> () {
- desc { "trigger a delay span bug" }
+ desc { "triggering a delay span bug" }
}
- query resolutions(_: ()) -> &'tcx ty::ResolverOutputs {
+ query resolutions(_: ()) -> &'tcx ty::ResolverGlobalCtxt {
eval_always
no_hash
- desc { "get the resolver outputs" }
+ desc { "getting the resolver outputs" }
}
query resolver_for_lowering(_: ()) -> &'tcx Steal<ty::ResolverAstLowering> {
eval_always
no_hash
- desc { "get the resolver for lowering" }
+ desc { "getting the resolver for lowering" }
}
/// Return the span for a definition.
@@ -37,7 +40,7 @@ rustc_queries! {
/// This span is meant for dep-tracking rather than diagnostics. It should not be used outside
/// of rustc_middle::hir::source_map.
query source_span(key: LocalDefId) -> Span {
- desc { "get the source span" }
+ desc { "getting the source span" }
}
/// Represents crate as a whole (as distinct from the top-level crate module).
@@ -49,14 +52,14 @@ rustc_queries! {
query hir_crate(key: ()) -> Crate<'tcx> {
arena_cache
eval_always
- desc { "get the crate HIR" }
+ desc { "getting the crate HIR" }
}
/// All items in the crate.
query hir_crate_items(_: ()) -> rustc_middle::hir::ModuleItems {
arena_cache
eval_always
- desc { "get HIR crate items" }
+ desc { "getting HIR crate items" }
}
/// The items in a module.
@@ -65,7 +68,7 @@ rustc_queries! {
/// Avoid calling this query directly.
query hir_module_items(key: LocalDefId) -> rustc_middle::hir::ModuleItems {
arena_cache
- desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
cache_on_disk_if { true }
}
@@ -73,8 +76,8 @@ rustc_queries! {
///
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
- query hir_owner(key: LocalDefId) -> Option<crate::hir::Owner<'tcx>> {
- desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
+ 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()) }
}
/// Gives access to the HIR ID for the given `LocalDefId` owner `key`.
@@ -82,31 +85,31 @@ rustc_queries! {
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
query local_def_id_to_hir_id(key: LocalDefId) -> hir::HirId {
- desc { |tcx| "HIR ID of `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting HIR ID of `{}`", tcx.def_path_str(key.to_def_id()) }
}
/// Gives access to the HIR node's parent for the HIR owner `key`.
///
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
- query hir_owner_parent(key: LocalDefId) -> hir::HirId {
- desc { |tcx| "HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) }
+ query hir_owner_parent(key: hir::OwnerId) -> hir::HirId {
+ desc { |tcx| "getting HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) }
}
/// Gives access to the HIR nodes and bodies inside the HIR owner `key`.
///
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
- query hir_owner_nodes(key: LocalDefId) -> hir::MaybeOwner<&'tcx hir::OwnerNodes<'tcx>> {
- desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
+ 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()) }
}
/// Gives access to the HIR attributes inside the HIR owner `key`.
///
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
- query hir_attrs(key: LocalDefId) -> &'tcx hir::AttributeMap<'tcx> {
- desc { |tcx| "HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) }
+ 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
@@ -135,7 +138,7 @@ rustc_queries! {
/// Given the def_id of a const-generic parameter, computes the associated default const
/// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
query const_param_default(param: DefId) -> ty::Const<'tcx> {
- desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param) }
+ desc { |tcx| "computing const default for a given parameter `{}`", tcx.def_path_str(param) }
cache_on_disk_if { param.is_local() }
separate_provide_extern
}
@@ -164,7 +167,7 @@ rustc_queries! {
query collect_trait_impl_trait_tys(key: DefId)
-> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>
{
- desc { "compare an impl and trait method signature, inferring any hidden `impl Trait` types in the process" }
+ desc { "comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process" }
cache_on_disk_if { key.is_local() }
separate_provide_extern
}
@@ -274,19 +277,24 @@ rustc_queries! {
separate_provide_extern
}
- query lint_levels(_: ()) -> LintLevelMap {
+ query shallow_lint_levels_on(key: hir::OwnerId) -> rustc_middle::lint::ShallowLintLevelMap {
+ eval_always // fetches `resolutions`
arena_cache
- eval_always
- desc { "computing the lint levels for items in this crate" }
+ desc { |tcx| "looking up lint levels for `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ query lint_expectations(_: ()) -> Vec<(LintExpectationId, LintExpectation)> {
+ arena_cache
+ desc { "computing `#[expect]`ed lints in this crate" }
}
query parent_module_from_def_id(key: LocalDefId) -> LocalDefId {
eval_always
- desc { |tcx| "parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting the parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
}
query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
- desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
+ desc { |tcx| "getting the expansion that defined `{}`", tcx.def_path_str(key) }
separate_provide_extern
}
@@ -296,6 +304,32 @@ rustc_queries! {
separate_provide_extern
}
+ /// 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()) }
+ // infinitely sized types will cause a cycle
+ cycle_delay_bug
+ // we don't want recursive representability calls to be forced with
+ // incremental compilation because, if a cycle occurs, we need the
+ // entire cycle to be in memory for diagnostics
+ anon
+ }
+
+ /// An implementation detail for the `representability` query
+ query representability_adt_ty(_: Ty<'tcx>) -> rustc_middle::ty::Representability {
+ desc { "checking if `{}` is representable", key }
+ cycle_delay_bug
+ anon
+ }
+
+ /// Set of param indexes for type params that are in the type's representation
+ query params_in_repr(key: DefId) -> rustc_index::bit_set::BitSet<u32> {
+ desc { "finding type parameters in the representation" }
+ arena_cache
+ no_hash
+ separate_provide_extern
+ }
+
/// 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>
@@ -349,7 +383,7 @@ rustc_queries! {
/// See the README for the `mir` module for details.
query mir_const(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
desc {
- |tcx| "processing MIR for {}`{}`",
+ |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()),
}
@@ -361,7 +395,7 @@ rustc_queries! {
key: DefId
) -> Result<Option<&'tcx [ty::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
desc {
- |tcx| "building an abstract representation for {}", tcx.def_path_str(key),
+ |tcx| "building an abstract representation for `{}`", tcx.def_path_str(key),
}
separate_provide_extern
}
@@ -371,16 +405,16 @@ rustc_queries! {
) -> Result<Option<&'tcx [ty::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
desc {
|tcx|
- "building an abstract representation for the const argument {}",
+ "building an abstract representation for the const argument `{}`",
tcx.def_path_str(key.0.to_def_id()),
}
}
query try_unify_abstract_consts(key:
- ty::ParamEnvAnd<'tcx, (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>
+ ty::ParamEnvAnd<'tcx, (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>
)>) -> bool {
desc {
- |tcx| "trying to unify the generic constants {} and {}",
+ |tcx| "trying to unify the generic constants `{}` and `{}`",
tcx.def_path_str(key.value.0.def.did), tcx.def_path_str(key.value.1.def.did)
}
}
@@ -402,7 +436,7 @@ rustc_queries! {
query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
desc {
- |tcx| "MIR for CTFE of the const argument `{}`",
+ |tcx| "caching MIR for CTFE of the const argument `{}`",
tcx.def_path_str(key.0.to_def_id())
}
}
@@ -414,7 +448,7 @@ rustc_queries! {
) {
no_hash
desc {
- |tcx| "processing {}`{}`",
+ |tcx| "processing MIR for {}`{}`",
if key.const_param_did.is_some() { "the const argument " } else { "" },
tcx.def_path_str(key.did.to_def_id()),
}
@@ -425,7 +459,7 @@ rustc_queries! {
) -> Vec<rustc_span::Symbol> {
arena_cache
desc {
- |tcx| "symbols for captures of closure `{}` in `{}`",
+ |tcx| "finding symbols for captures of closure `{}` in `{}`",
tcx.def_path_str(key.1.to_def_id()),
tcx.def_path_str(key.0.to_def_id())
}
@@ -487,12 +521,12 @@ rustc_queries! {
// queries). Making it anonymous avoids hashing the result, which
// may save a bit of time.
anon
- desc { "erasing regions from `{:?}`", ty }
+ desc { "erasing regions from `{}`", ty }
}
query wasm_import_module_map(_: CrateNum) -> FxHashMap<DefId, String> {
arena_cache
- desc { "wasm import module map" }
+ desc { "getting wasm import module map" }
}
/// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
@@ -582,16 +616,8 @@ rustc_queries! {
separate_provide_extern
}
- // The cycle error here should be reported as an error by `check_representable`.
- // We consider the type as Sized in the meanwhile to avoid
- // further errors (done in impl Value for AdtSizedConstraint).
- // Use `cycle_delay_bug` to delay the cycle error here to be emitted later
- // in case we accidentally otherwise don't emit an error.
- query adt_sized_constraint(
- key: DefId
- ) -> AdtSizedConstraint<'tcx> {
+ query adt_sized_constraint(key: DefId) -> &'tcx [Ty<'tcx>] {
desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) }
- cycle_delay_bug
}
query adt_dtorck_constraint(
@@ -680,7 +706,7 @@ rustc_queries! {
/// Collects the associated items defined on a trait or impl.
query associated_items(key: DefId) -> ty::AssocItems<'tcx> {
arena_cache
- desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) }
+ desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
}
/// Maps from associated items on a trait to the corresponding associated
@@ -706,7 +732,7 @@ rustc_queries! {
///`{ trait_f: impl_f, trait_g: impl_g }`
query impl_item_implementor_ids(impl_id: DefId) -> FxHashMap<DefId, DefId> {
arena_cache
- desc { |tcx| "comparing impl items against trait for {}", tcx.def_path_str(impl_id) }
+ desc { |tcx| "comparing impl items against trait for `{}`", tcx.def_path_str(impl_id) }
}
/// Given an `impl_id`, return the trait it implements.
@@ -778,7 +804,7 @@ rustc_queries! {
/// Note that we've liberated the late bound regions of function signatures, so
/// this can not be used to check whether these types are well formed.
query assumed_wf_types(key: DefId) -> &'tcx ty::List<Ty<'tcx>> {
- desc { |tcx| "computing the implied bounds of {}", tcx.def_path_str(key) }
+ desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) }
}
/// Computes the signature of the function.
@@ -827,7 +853,7 @@ rustc_queries! {
}
query check_liveness(key: DefId) {
- desc { |tcx| "checking liveness of variables in {}", tcx.def_path_str(key) }
+ desc { |tcx| "checking liveness of variables in `{}`", tcx.def_path_str(key) }
}
/// Return the live symbols in the crate for dead code check.
@@ -839,7 +865,7 @@ rustc_queries! {
FxHashMap<LocalDefId, Vec<(DefId, DefId)>>
) {
arena_cache
- desc { "find live symbols in crate" }
+ desc { "finding live symbols in crate" }
}
query check_mod_deathness(key: LocalDefId) -> () {
@@ -886,8 +912,8 @@ rustc_queries! {
cache_on_disk_if { true }
}
- query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet<LocalDefId> {
- desc { |tcx| "used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) }
+ query used_trait_imports(key: LocalDefId) -> &'tcx UnordSet<LocalDefId> {
+ desc { |tcx| "finding used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) }
cache_on_disk_if { true }
}
@@ -916,7 +942,7 @@ rustc_queries! {
/// Not meant to be used directly outside of coherence.
query crate_inherent_impls(k: ()) -> CrateInherentImpls {
arena_cache
- desc { "all inherent impls defined in crate" }
+ desc { "finding all inherent impls defined in crate" }
}
/// Checks all types in the crate for overlap in their inherent impls. Reports errors.
@@ -1003,8 +1029,10 @@ rustc_queries! {
/// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index
/// and its field values.
- query try_destructure_mir_constant(key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>) -> Option<mir::DestructuredMirConstant<'tcx>> {
- desc { "destructuring mir constant"}
+ query try_destructure_mir_constant(
+ key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
+ ) -> Option<mir::DestructuredConstant<'tcx>> {
+ desc { "destructuring MIR constant"}
remap_env_constness
}
@@ -1013,12 +1041,12 @@ rustc_queries! {
query deref_mir_constant(
key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
) -> mir::ConstantKind<'tcx> {
- desc { "dereferencing mir constant" }
+ desc { "dereferencing MIR constant" }
remap_env_constness
}
query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {
- desc { "get a &core::panic::Location referring to a span" }
+ desc { "getting a &core::panic::Location referring to a span" }
}
// FIXME get rid of this with valtrees
@@ -1037,10 +1065,10 @@ rustc_queries! {
cache_on_disk_if { key.is_local() }
}
- /// Performs part of the privacy check and computes "access levels".
- query privacy_access_levels(_: ()) -> &'tcx AccessLevels {
+ /// Performs part of the privacy check and computes effective visibilities.
+ query effective_visibilities(_: ()) -> &'tcx EffectiveVisibilities {
eval_always
- desc { "privacy access levels" }
+ desc { "checking effective visibilities" }
}
query check_private_in_public(_: ()) -> () {
eval_always
@@ -1124,6 +1152,11 @@ rustc_queries! {
desc { |tcx| "checking whether `{}` is `doc(hidden)`", tcx.def_path_str(def_id) }
}
+ /// Determines whether an item is annotated with `doc(notable_trait)`.
+ query is_doc_notable_trait(def_id: DefId) -> bool {
+ desc { |tcx| "checking whether `{}` is `doc(notable_trait)`", tcx.def_path_str(def_id) }
+ }
+
/// Returns the attributes on the item at `def_id`.
///
/// Do not use this directly, use `tcx.get_attrs` instead.
@@ -1163,29 +1196,29 @@ rustc_queries! {
}
query is_ctfe_mir_available(key: DefId) -> bool {
- desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) }
+ desc { |tcx| "checking if item has CTFE MIR available: `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
separate_provide_extern
}
query is_mir_available(key: DefId) -> bool {
- desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
+ desc { |tcx| "checking if item has MIR available: `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
separate_provide_extern
}
query own_existential_vtable_entries(
- key: ty::PolyExistentialTraitRef<'tcx>
+ key: DefId
) -> &'tcx [DefId] {
- desc { |tcx| "finding all existential vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
+ desc { |tcx| "finding all existential vtable entries for trait `{}`", tcx.def_path_str(key) }
}
query vtable_entries(key: ty::PolyTraitRef<'tcx>)
-> &'tcx [ty::VtblEntry<'tcx>] {
- desc { |tcx| "finding all vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
+ desc { |tcx| "finding all vtable entries for trait `{}`", tcx.def_path_str(key.def_id()) }
}
- query vtable_trait_upcasting_coercion_new_vptr_slot(key: (ty::Ty<'tcx>, ty::Ty<'tcx>)) -> Option<usize> {
- desc { |tcx| "finding the slot within vtable for trait object {} vtable ptr during trait upcasting coercion from {} vtable",
+ query vtable_trait_upcasting_coercion_new_vptr_slot(key: (Ty<'tcx>, Ty<'tcx>)) -> Option<usize> {
+ desc { |tcx| "finding the slot within vtable for trait object `{}` vtable ptr during trait upcasting coercion from `{}` vtable",
key.1, key.0 }
}
@@ -1205,13 +1238,13 @@ rustc_queries! {
/// Return all `impl` blocks in the current crate.
query all_local_trait_impls(_: ()) -> &'tcx rustc_data_structures::fx::FxIndexMap<DefId, Vec<LocalDefId>> {
- desc { "local trait impls" }
+ desc { "finding local trait impls" }
}
/// Given a trait `trait_id`, return all known `impl` blocks.
query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls {
arena_cache
- desc { |tcx| "trait impls of `{}`", tcx.def_path_str(trait_id) }
+ desc { |tcx| "finding trait impls of `{}`", tcx.def_path_str(trait_id) }
}
query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph {
@@ -1220,7 +1253,7 @@ rustc_queries! {
cache_on_disk_if { true }
}
query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
- desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(trait_id) }
+ desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) }
}
/// Gets the ParameterEnvironment for a given item; this environment
@@ -1278,7 +1311,7 @@ rustc_queries! {
/// correctly.
query has_structural_eq_impls(ty: Ty<'tcx>) -> bool {
desc {
- "computing whether `{:?}` implements `PartialStructuralEq` and `StructuralEq`",
+ "computing whether `{}` implements `PartialStructuralEq` and `StructuralEq`",
ty
}
}
@@ -1337,13 +1370,13 @@ rustc_queries! {
query dylib_dependency_formats(_: CrateNum)
-> &'tcx [(CrateNum, LinkagePreference)] {
- desc { "dylib dependency formats of crate" }
+ desc { "getting dylib dependency formats of crate" }
separate_provide_extern
}
query dependency_formats(_: ()) -> Lrc<crate::middle::dependency_format::Dependencies> {
arena_cache
- desc { "get the linkage format of all dependencies" }
+ desc { "getting the linkage format of all dependencies" }
}
query is_compiler_builtins(_: CrateNum) -> bool {
@@ -1365,31 +1398,31 @@ rustc_queries! {
}
query is_profiler_runtime(_: CrateNum) -> bool {
fatal_cycle
- desc { "query a crate is `#![profiler_runtime]`" }
+ desc { "checking if a crate is `#![profiler_runtime]`" }
separate_provide_extern
}
query has_ffi_unwind_calls(key: LocalDefId) -> bool {
- desc { |tcx| "check 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.to_def_id()) }
cache_on_disk_if { true }
}
query required_panic_strategy(_: CrateNum) -> Option<PanicStrategy> {
fatal_cycle
- desc { "query a crate's required panic strategy" }
+ desc { "getting a crate's required panic strategy" }
separate_provide_extern
}
query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy {
fatal_cycle
- desc { "query a crate's configured panic-in-drop strategy" }
+ desc { "getting a crate's configured panic-in-drop strategy" }
separate_provide_extern
}
query is_no_builtins(_: CrateNum) -> bool {
fatal_cycle
- desc { "test whether a crate has `#![no_builtins]`" }
+ desc { "getting whether a crate has `#![no_builtins]`" }
separate_provide_extern
}
query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion {
fatal_cycle
- desc { "query a crate's symbol mangling version" }
+ desc { "getting a crate's symbol mangling version" }
separate_provide_extern
}
@@ -1402,9 +1435,9 @@ rustc_queries! {
query specializes(_: (DefId, DefId)) -> bool {
desc { "computing whether impls specialize one another" }
}
- query in_scope_traits_map(_: LocalDefId)
+ query in_scope_traits_map(_: hir::OwnerId)
-> Option<&'tcx FxHashMap<ItemLocalId, Box<[TraitCandidate]>>> {
- desc { "traits in scope at a block" }
+ desc { "getting traits in scope at a block" }
}
query module_reexports(def_id: LocalDefId) -> Option<&'tcx [ModChild]> {
@@ -1417,7 +1450,7 @@ rustc_queries! {
separate_provide_extern
}
- query check_well_formed(key: LocalDefId) -> () {
+ query check_well_formed(key: hir::OwnerId) -> () {
desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) }
}
@@ -1554,18 +1587,8 @@ rustc_queries! {
separate_provide_extern
}
- query is_dllimport_foreign_item(def_id: DefId) -> bool {
- desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) }
- }
- query is_statically_included_foreign_item(def_id: DefId) -> bool {
- desc { |tcx| "is_statically_included_foreign_item({})", tcx.def_path_str(def_id) }
- }
- query native_library_kind(def_id: DefId)
- -> Option<NativeLibKind> {
- desc { |tcx| "native_library_kind({})", tcx.def_path_str(def_id) }
- }
query native_library(def_id: DefId) -> Option<&'tcx NativeLib> {
- desc { |tcx| "native_library({})", tcx.def_path_str(def_id) }
+ desc { |tcx| "getting the native library for `{}`", tcx.def_path_str(def_id) }
}
/// Does lifetime resolution, but does not descend into trait items. This
@@ -1584,7 +1607,7 @@ rustc_queries! {
arena_cache
desc { "resolving lifetimes" }
}
- query named_region_map(_: LocalDefId) ->
+ query named_region_map(_: hir::OwnerId) ->
Option<&'tcx FxHashMap<ItemLocalId, Region>> {
desc { "looking up a named region" }
}
@@ -1600,7 +1623,7 @@ rustc_queries! {
desc { "looking up lifetime defaults for generic parameter `{}`", tcx.def_path_str(key) }
separate_provide_extern
}
- query late_bound_vars_map(_: LocalDefId)
+ query late_bound_vars_map(_: hir::OwnerId)
-> Option<&'tcx FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>> {
desc { "looking up late bound vars" }
}
@@ -1620,14 +1643,13 @@ rustc_queries! {
separate_provide_extern
}
- /// Computes the set of modules from which this type is visibly uninhabited.
- /// To check whether a type is uninhabited at all (not just from a given module), you could
- /// check whether the forest is empty.
- query type_uninhabited_from(
- key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
- ) -> ty::inhabitedness::DefIdForest<'tcx> {
- desc { "computing the inhabitedness of `{:?}`", key }
- remap_env_constness
+ query inhabited_predicate_adt(key: DefId) -> ty::inhabitedness::InhabitedPredicate<'tcx> {
+ desc { "computing the uninhabited predicate of `{:?}`", key }
+ }
+
+ /// Do not call this query directly: invoke `Ty::inhabited_predicate` instead.
+ query inhabited_predicate_type(key: Ty<'tcx>) -> ty::inhabitedness::InhabitedPredicate<'tcx> {
+ desc { "computing the uninhabited predicate of `{}`", key }
}
query dep_kind(_: CrateNum) -> CrateDepKind {
@@ -1665,7 +1687,7 @@ rustc_queries! {
}
/// Whether the function is an intrinsic
query is_intrinsic(def_id: DefId) -> bool {
- desc { |tcx| "is_intrinsic({})", tcx.def_path_str(def_id) }
+ desc { |tcx| "checking whether `{}` is an intrinsic", tcx.def_path_str(def_id) }
separate_provide_extern
}
/// Returns the lang items defined in another crate by loading it from metadata.
@@ -1732,12 +1754,12 @@ rustc_queries! {
/// is marked as a private dependency
query is_private_dep(c: CrateNum) -> bool {
eval_always
- desc { "check whether crate {} is a private dependency", c }
+ desc { "checking whether crate `{}` is a private dependency", c }
separate_provide_extern
}
query allocator_kind(_: ()) -> Option<AllocatorKind> {
eval_always
- desc { "allocator kind for the current crate" }
+ desc { "getting the allocator kind for the current crate" }
}
query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
@@ -1750,7 +1772,7 @@ rustc_queries! {
desc { "looking up all possibly unused extern crates" }
}
query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx FxHashSet<Symbol> {
- desc { |tcx| "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.to_def_id()) }
}
query stability_index(_: ()) -> stability::Index {
@@ -1776,7 +1798,7 @@ rustc_queries! {
/// correspond to a publicly visible symbol in `cnum` machine code.
/// - The `exported_symbols` sets of different crates do not intersect.
query exported_symbols(cnum: CrateNum) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
- desc { "exported_symbols" }
+ desc { "collecting exported symbols for crate `{}`", cnum}
cache_on_disk_if { *cnum == LOCAL_CRATE }
separate_provide_extern
}
@@ -1785,6 +1807,7 @@ rustc_queries! {
eval_always
desc { "collect_and_partition_mono_items" }
}
+
query is_codegened_item(def_id: DefId) -> bool {
desc { |tcx| "determining whether `{}` needs codegen", tcx.def_path_str(def_id) }
}
@@ -1792,12 +1815,13 @@ rustc_queries! {
/// All items participating in code generation together with items inlined into them.
query codegened_and_inlined_items(_: ()) -> &'tcx DefIdSet {
eval_always
- desc { "codegened_and_inlined_items" }
+ desc { "collecting codegened and inlined items" }
}
- query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> {
- desc { "codegen_unit" }
+ query codegen_unit(sym: Symbol) -> &'tcx CodegenUnit<'tcx> {
+ desc { "getting codegen unit `{sym}`" }
}
+
query unused_generic_params(key: ty::InstanceDef<'tcx>) -> FiniteBitSet<u32> {
cache_on_disk_if { key.def_id().is_local() }
desc {
@@ -1806,6 +1830,7 @@ rustc_queries! {
}
separate_provide_extern
}
+
query backend_optimization_level(_: ()) -> OptLevel {
desc { "optimization level used by backend" }
}
@@ -1816,7 +1841,7 @@ rustc_queries! {
/// has been destroyed.
query output_filenames(_: ()) -> &'tcx Arc<OutputFilenames> {
eval_always
- desc { "output_filenames" }
+ desc { "getting output filenames" }
}
/// Do not call this query directly: invoke `normalize` instead.
@@ -1826,7 +1851,7 @@ rustc_queries! {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
NoSolution,
> {
- desc { "normalizing `{:?}`", goal }
+ desc { "normalizing `{}`", goal.value.value }
remap_env_constness
}
@@ -1838,21 +1863,13 @@ rustc_queries! {
remap_env_constness
}
- /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
- query try_normalize_mir_const_after_erasing_regions(
- goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
- ) -> Result<mir::ConstantKind<'tcx>, NoSolution> {
- desc { "normalizing `{}`", goal.value }
- remap_env_constness
- }
-
query implied_outlives_bounds(
goal: CanonicalTyGoal<'tcx>
) -> Result<
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
NoSolution,
> {
- desc { "computing implied outlives bounds for `{:?}`", goal }
+ desc { "computing implied outlives bounds for `{}`", goal.value.value }
remap_env_constness
}
@@ -1864,7 +1881,7 @@ rustc_queries! {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>,
NoSolution,
> {
- desc { "computing dropck types for `{:?}`", goal }
+ desc { "computing dropck types for `{}`", goal.value.value }
remap_env_constness
}
@@ -1892,7 +1909,7 @@ rustc_queries! {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
NoSolution,
> {
- desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal }
+ desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal.value.value }
remap_env_constness
}
@@ -1903,7 +1920,7 @@ rustc_queries! {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
NoSolution,
> {
- desc { "evaluating `type_op_eq` `{:?}`", goal }
+ desc { "evaluating `type_op_eq` `{:?}`", goal.value.value }
remap_env_constness
}
@@ -1914,7 +1931,7 @@ rustc_queries! {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
NoSolution,
> {
- desc { "evaluating `type_op_subtype` `{:?}`", goal }
+ desc { "evaluating `type_op_subtype` `{:?}`", goal.value.value }
remap_env_constness
}
@@ -1925,7 +1942,7 @@ rustc_queries! {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
NoSolution,
> {
- desc { "evaluating `type_op_prove_predicate` `{:?}`", goal }
+ desc { "evaluating `type_op_prove_predicate` `{:?}`", goal.value.value }
}
/// Do not call this query directly: part of the `Normalize` type-op
@@ -1935,7 +1952,7 @@ rustc_queries! {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Ty<'tcx>>>,
NoSolution,
> {
- desc { "normalizing `{:?}`", goal }
+ desc { "normalizing `{}`", goal.value.value.value }
remap_env_constness
}
@@ -1946,7 +1963,7 @@ rustc_queries! {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Predicate<'tcx>>>,
NoSolution,
> {
- desc { "normalizing `{:?}`", goal }
+ desc { "normalizing `{:?}`", goal.value.value.value }
remap_env_constness
}
@@ -1957,7 +1974,7 @@ rustc_queries! {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::PolyFnSig<'tcx>>>,
NoSolution,
> {
- desc { "normalizing `{:?}`", goal }
+ desc { "normalizing `{:?}`", goal.value.value.value }
remap_env_constness
}
@@ -1968,20 +1985,20 @@ rustc_queries! {
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::FnSig<'tcx>>>,
NoSolution,
> {
- desc { "normalizing `{:?}`", goal }
+ desc { "normalizing `{:?}`", goal.value.value.value }
remap_env_constness
}
query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
desc { |tcx|
- "impossible substituted predicates:`{}`",
+ "checking impossible substituted predicates: `{}`",
tcx.def_path_str(key.0)
}
}
query is_impossible_method(key: (DefId, DefId)) -> bool {
desc { |tcx|
- "checking if {} is impossible to call within {}",
+ "checking if `{}` is impossible to call within `{}`",
tcx.def_path_str(key.1),
tcx.def_path_str(key.0),
}
@@ -1990,7 +2007,7 @@ rustc_queries! {
query method_autoderef_steps(
goal: CanonicalTyGoal<'tcx>
) -> MethodAutoderefStepsResult<'tcx> {
- desc { "computing autoderef types for `{:?}`", goal }
+ desc { "computing autoderef types for `{}`", goal.value.value }
remap_env_constness
}
@@ -2038,7 +2055,7 @@ rustc_queries! {
}
query normalize_opaque_types(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
- desc { "normalizing opaque types in {:?}", key }
+ desc { "normalizing opaque types in `{:?}`", key }
}
/// Checks whether a type is definitely uninhabited. This is
@@ -2048,7 +2065,7 @@ rustc_queries! {
/// will be `Abi::Uninhabited`. (Note that uninhabited types may have nonzero
/// size, to account for partial initialisation. See #49298 for details.)
query conservative_is_privately_uninhabited(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
- desc { "conservatively checking if {:?} is privately uninhabited", key }
+ desc { "conservatively checking if `{}` is privately uninhabited", key.value }
remap_env_constness
}
@@ -2068,7 +2085,7 @@ rustc_queries! {
arena_cache
eval_always
no_hash
- desc { "performing HIR wf-checking for predicate {:?} at item {:?}", key.0, key.1 }
+ desc { "performing HIR wf-checking for predicate `{:?}` at item `{:?}`", key.0, key.1 }
}
@@ -2087,10 +2104,21 @@ rustc_queries! {
}
query permits_uninit_init(key: TyAndLayout<'tcx>) -> bool {
- desc { "checking to see if {:?} permits being left uninit", key.ty }
+ desc { "checking to see if `{}` permits being left uninit", key.ty }
}
query permits_zero_init(key: TyAndLayout<'tcx>) -> bool {
- desc { "checking to see if {:?} permits being left zeroed", key.ty }
+ desc { "checking to see if `{}` permits being left zeroed", key.ty }
+ }
+
+ query compare_assoc_const_impl_item_with_trait_item(
+ 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()) }
+ }
+
+ query deduced_param_attrs(def_id: DefId) -> &'tcx [ty::DeducedParamAttrs] {
+ desc { |tcx| "deducing parameter attributes for {}", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
}
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 86b415050..ea7a507d7 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -203,7 +203,7 @@ pub enum StmtKind<'tcx> {
/// `let pat: ty = <INIT>`
initializer: Option<ExprId>,
- /// `let pat: ty = <INIT> else { <ELSE> }
+ /// `let pat: ty = <INIT> else { <ELSE> }`
else_block: Option<BlockId>,
/// The lint level for this `let` statement.
@@ -848,16 +848,13 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
mod size_asserts {
use super::*;
- // These are in alphabetical order, which is easy to maintain.
+ // tidy-alphabetical-start
static_assert_size!(Block, 56);
static_assert_size!(Expr<'_>, 64);
static_assert_size!(ExprKind<'_>, 40);
- #[cfg(not(bootstrap))]
static_assert_size!(Pat<'_>, 72);
- #[cfg(not(bootstrap))]
static_assert_size!(PatKind<'_>, 56);
- #[cfg(not(bootstrap))]
static_assert_size!(Stmt<'_>, 48);
- #[cfg(not(bootstrap))]
static_assert_size!(StmtKind<'_>, 40);
+ // tidy-alphabetical-end
}
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 68a7af0b8..e73d44bbb 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -598,11 +598,6 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
/// // type parameters, ImplSource will carry resolutions for those as well:
/// concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])])
///
-/// // Case A: ImplSource points at a specific impl. Only possible when
-/// // type is concretely known. If the impl itself has bounded
-/// // type parameters, ImplSource will carry resolutions for those as well:
-/// concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])])
-///
/// // Case B: ImplSource must be provided by caller. This applies when
/// // type is a type parameter.
/// param.clone(); // ImplSource::Param
@@ -664,10 +659,6 @@ pub enum ImplSource<'tcx, N> {
/// ImplSource for a `const Drop` implementation.
ConstDestruct(ImplSourceConstDestructData<N>),
-
- /// ImplSource for a `std::marker::Tuple` implementation.
- /// This has no nested predicates ever, so no data.
- Tuple,
}
impl<'tcx, N> ImplSource<'tcx, N> {
@@ -682,8 +673,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
ImplSource::Object(d) => d.nested,
ImplSource::FnPointer(d) => d.nested,
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
- | ImplSource::Pointee(ImplSourcePointeeData)
- | ImplSource::Tuple => Vec::new(),
+ | ImplSource::Pointee(ImplSourcePointeeData) => vec![],
ImplSource::TraitAlias(d) => d.nested,
ImplSource::TraitUpcasting(d) => d.nested,
ImplSource::ConstDestruct(i) => i.nested,
@@ -701,8 +691,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
ImplSource::Object(d) => &d.nested,
ImplSource::FnPointer(d) => &d.nested,
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
- | ImplSource::Pointee(ImplSourcePointeeData)
- | ImplSource::Tuple => &[],
+ | ImplSource::Pointee(ImplSourcePointeeData) => &[],
ImplSource::TraitAlias(d) => &d.nested,
ImplSource::TraitUpcasting(d) => &d.nested,
ImplSource::ConstDestruct(i) => &i.nested,
@@ -769,7 +758,6 @@ impl<'tcx, N> ImplSource<'tcx, N> {
nested: i.nested.into_iter().map(f).collect(),
})
}
- ImplSource::Tuple => ImplSource::Tuple,
}
}
}
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index 0e6cacb9f..fb152b63f 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -8,8 +8,9 @@
use crate::error::DropCheckOverflow;
use crate::infer::canonical::{Canonical, QueryResponse};
use crate::ty::error::TypeError;
-use crate::ty::subst::GenericArg;
+use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::{self, Ty, TyCtxt};
+use rustc_hir::def_id::DefId;
use rustc_span::source_map::Span;
use std::iter::FromIterator;
@@ -219,4 +220,5 @@ pub enum OutlivesBound<'tcx> {
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
+ RegionSubOpaque(ty::Region<'tcx>, DefId, SubstsRef<'tcx>),
}
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 53af3e905..85ead3171 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -115,12 +115,13 @@ pub enum SelectionCandidate<'tcx> {
ParamCandidate(ty::PolyTraitPredicate<'tcx>),
ImplCandidate(DefId),
- AutoImplCandidate(DefId),
+ AutoImplCandidate,
/// This is a trait matching with a projected type as `Self`, and we found
/// an applicable bound in the trait definition. The `usize` is an index
- /// into the list returned by `tcx.item_bounds`.
- ProjectionCandidate(usize),
+ /// into the list returned by `tcx.item_bounds`. The constness is the
+ /// constness of the bound in the trait.
+ ProjectionCandidate(usize, ty::BoundConstness),
/// Implementation of a `Fn`-family trait by one of the anonymous types
/// generated for an `||` expression.
@@ -142,7 +143,7 @@ pub enum SelectionCandidate<'tcx> {
/// Builtin implementation of `Pointee`.
PointeeCandidate,
- TraitAliasCandidate(DefId),
+ TraitAliasCandidate,
/// Matching `dyn Trait` with a supertrait of `Trait`. The index is the
/// position in the iterator returned by
@@ -160,9 +161,6 @@ pub enum SelectionCandidate<'tcx> {
/// Implementation of `const Destruct`, optionally from a custom `impl const Drop`.
ConstDestructCandidate(Option<DefId>),
-
- /// Witnesses the fact that a type is a tuple.
- TupleCandidate,
}
/// The result of trait evaluation. The order is important
diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs
index c526344e1..7fbd57ac7 100644
--- a/compiler/rustc_middle/src/traits/structural_impls.rs
+++ b/compiler/rustc_middle/src/traits/structural_impls.rs
@@ -34,8 +34,6 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
super::ImplSource::ConstDestruct(ref d) => write!(f, "{:?}", d),
-
- super::ImplSource::Tuple => write!(f, "ImplSource::Tuple"),
}
}
}
diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs
index 8f79b4705..1aa4df778 100644
--- a/compiler/rustc_middle/src/ty/abstract_const.rs
+++ b/compiler/rustc_middle/src/ty/abstract_const.rs
@@ -1,7 +1,7 @@
//! A subset of a mir body used for const evaluatability checking.
use crate::mir;
use crate::ty::visit::TypeVisitable;
-use crate::ty::{self, subst::Subst, DelaySpanBugEmitted, EarlyBinder, SubstsRef, Ty, TyCtxt};
+use crate::ty::{self, DelaySpanBugEmitted, EarlyBinder, SubstsRef, Ty, TyCtxt};
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::DefId;
use std::cmp;
@@ -30,7 +30,7 @@ pub struct AbstractConst<'tcx> {
impl<'tcx> AbstractConst<'tcx> {
pub fn new(
tcx: TyCtxt<'tcx>,
- uv: ty::Unevaluated<'tcx, ()>,
+ uv: ty::UnevaluatedConst<'tcx>,
) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> {
let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?;
debug!("AbstractConst::new({:?}) = {:?}", uv, inner);
@@ -71,16 +71,16 @@ impl<'tcx> AbstractConst<'tcx> {
walk_abstract_const::<!, _>(tcx, self, |node| {
match node.root(tcx) {
Node::Leaf(leaf) => {
- if leaf.has_infer_types_or_consts() {
+ if leaf.has_non_region_infer() {
failure_kind = FailureKind::MentionsInfer;
- } else if leaf.has_param_types_or_consts() {
+ } else if leaf.has_non_region_param() {
failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
}
}
Node::Cast(_, _, ty) => {
- if ty.has_infer_types_or_consts() {
+ if ty.has_non_region_infer() {
failure_kind = FailureKind::MentionsInfer;
- } else if ty.has_param_types_or_consts() {
+ } else if ty.has_non_region_param() {
failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
}
}
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index b809f1767..4682ac96b 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -101,6 +101,9 @@ pub enum Adjust<'tcx> {
Borrow(AutoBorrow<'tcx>),
Pointer(PointerCast),
+
+ /// Cast into a dyn* object.
+ DynStar,
}
/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 2e596b275..b0a2412ab 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -26,9 +26,6 @@ use super::{
Destructor, FieldDef, GenericPredicates, ReprOptions, Ty, TyCtxt, VariantDef, VariantDiscr,
};
-#[derive(Copy, Clone, HashStable, Debug)]
-pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]);
-
bitflags! {
#[derive(HashStable, TyEncodable, TyDecodable)]
pub struct AdtFlags: u32 {
@@ -332,13 +329,13 @@ impl<'tcx> AdtDef<'tcx> {
self.flags().contains(AdtFlags::IS_PHANTOM_DATA)
}
- /// Returns `true` if this is Box<T>.
+ /// Returns `true` if this is `Box<T>`.
#[inline]
pub fn is_box(self) -> bool {
self.flags().contains(AdtFlags::IS_BOX)
}
- /// Returns `true` if this is UnsafeCell<T>.
+ /// Returns `true` if this is `UnsafeCell<T>`.
#[inline]
pub fn is_unsafe_cell(self) -> bool {
self.flags().contains(AdtFlags::IS_UNSAFE_CELL)
@@ -438,7 +435,8 @@ impl<'tcx> AdtDef<'tcx> {
| Res::Def(DefKind::Union, _)
| Res::Def(DefKind::TyAlias, _)
| Res::Def(DefKind::AssocTy, _)
- | Res::SelfTy { .. }
+ | Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. }
| Res::SelfCtor(..) => self.non_enum_variant(),
_ => bug!("unexpected res {:?} in variant_of_res", res),
}
@@ -457,11 +455,9 @@ impl<'tcx> AdtDef<'tcx> {
Some(Discr { val: b, ty })
} else {
info!("invalid enum discriminant: {:#?}", val);
- crate::mir::interpret::struct_error(
- tcx.at(tcx.def_span(expr_did)),
- "constant evaluation of enum discriminant resulted in non-integer",
- )
- .emit();
+ tcx.sess.emit_err(crate::error::ConstEvalNonIntError {
+ span: tcx.def_span(expr_did),
+ });
None
}
}
@@ -564,6 +560,13 @@ impl<'tcx> AdtDef<'tcx> {
/// Due to normalization being eager, this applies even if
/// the associated type is behind a pointer (e.g., issue #31299).
pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> {
- ty::EarlyBinder(tcx.adt_sized_constraint(self.did()).0)
+ ty::EarlyBinder(tcx.adt_sized_constraint(self.did()))
}
}
+
+#[derive(Clone, Copy, Debug)]
+#[derive(HashStable)]
+pub enum Representability {
+ Representable,
+ Infinite,
+}
diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs
index 981e2d3b6..e65585955 100644
--- a/compiler/rustc_middle/src/ty/cast.rs
+++ b/compiler/rustc_middle/src/ty/cast.rs
@@ -2,6 +2,7 @@
// typeck and codegen.
use crate::ty::{self, Ty};
+use rustc_middle::mir;
use rustc_macros::HashStable;
@@ -38,7 +39,7 @@ pub enum CastTy<'tcx> {
}
/// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html)
-/// (or librustc_typeck/check/cast.rs).
+/// (or rustc_hir_analysis/check/cast.rs).
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
pub enum CastKind {
CoercionCast,
@@ -75,3 +76,28 @@ impl<'tcx> CastTy<'tcx> {
}
}
}
+
+/// Returns `mir::CastKind` from the given parameters.
+pub fn mir_cast_kind<'tcx>(from_ty: Ty<'tcx>, cast_ty: Ty<'tcx>) -> mir::CastKind {
+ let from = CastTy::from_ty(from_ty);
+ let cast = CastTy::from_ty(cast_ty);
+ let cast_kind = match (from, cast) {
+ (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
+ mir::CastKind::PointerExposeAddress
+ }
+ (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PointerFromExposedAddress,
+ (_, Some(CastTy::DynStar)) => mir::CastKind::DynStar,
+ (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => mir::CastKind::IntToInt,
+ (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => mir::CastKind::FnPtrToPtr,
+
+ (Some(CastTy::Float), Some(CastTy::Int(_))) => mir::CastKind::FloatToInt,
+ (Some(CastTy::Int(_)), Some(CastTy::Float)) => mir::CastKind::IntToFloat,
+ (Some(CastTy::Float), Some(CastTy::Float)) => mir::CastKind::FloatToFloat,
+ (Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PtrToPtr,
+
+ (_, _) => {
+ bug!("Attempting to cast non-castable types {:?} and {:?}", from_ty, cast_ty)
+ }
+ };
+ cast_kind
+}
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 51137c526..14ec88b7e 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -455,6 +455,7 @@ impl_arena_copy_decoder! {<'tcx>
rustc_span::def_id::DefId,
rustc_span::def_id::LocalDefId,
(rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo),
+ ty::DeducedParamAttrs,
}
#[macro_export]
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 339ff4d35..f998e6083 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -1,9 +1,6 @@
use crate::mir::interpret::LitToConstInput;
use crate::mir::ConstantKind;
-use crate::ty::{
- self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty,
- TyCtxt, TypeVisitable,
-};
+use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
use rustc_data_structures::intern::Interned;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
@@ -81,10 +78,9 @@ impl<'tcx> Const<'tcx> {
match Self::try_eval_lit_or_param(tcx, ty, expr) {
Some(v) => v,
None => tcx.mk_const(ty::ConstS {
- kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
+ kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst {
def: def.to_global(),
substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
- promoted: (),
}),
ty,
}),
@@ -151,46 +147,6 @@ impl<'tcx> Const<'tcx> {
}
}
- pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
- debug!("Const::from_inline_const(def_id={:?})", def_id);
-
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-
- let body_id = match tcx.hir().get(hir_id) {
- hir::Node::AnonConst(ac) => ac.body,
- _ => span_bug!(
- tcx.def_span(def_id.to_def_id()),
- "from_inline_const can only process anonymous constants"
- ),
- };
-
- let expr = &tcx.hir().body(body_id).value;
-
- let ty = tcx.typeck(def_id).node_type(hir_id);
-
- let ret = match Self::try_eval_lit_or_param(tcx, ty, expr) {
- Some(v) => v,
- None => {
- let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
- let parent_substs =
- tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id));
- let substs =
- InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty })
- .substs;
- tcx.mk_const(ty::ConstS {
- kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
- def: ty::WithOptConstParam::unknown(def_id).to_global(),
- substs,
- promoted: (),
- }),
- ty,
- })
- }
- };
- debug_assert!(!ret.has_free_regions());
- ret
- }
-
/// Interns the given value as a constant.
#[inline]
pub fn from_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Self {
@@ -307,6 +263,10 @@ impl<'tcx> Const<'tcx> {
self.try_eval_usize(tcx, param_env)
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
}
+
+ pub fn is_ct_infer(self) -> bool {
+ matches!(self.kind(), ty::ConstKind::Infer(_))
+ }
}
pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Const<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index 455015280..4ab761e07 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -1,10 +1,11 @@
use std::convert::TryInto;
+use crate::mir;
use crate::mir::interpret::{AllocId, ConstValue, Scalar};
-use crate::mir::Promoted;
use crate::ty::subst::{InternalSubsts, SubstsRef};
use crate::ty::ParamEnv;
use crate::ty::{self, TyCtxt, TypeVisitable};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
@@ -12,40 +13,34 @@ use rustc_target::abi::Size;
use super::ScalarInt;
-/// An unevaluated, potentially generic, constant.
+/// An unevaluated (potentially generic) constant used in the type-system.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
-#[derive(Hash, HashStable)]
-pub struct Unevaluated<'tcx, P = Option<Promoted>> {
+#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
+pub struct UnevaluatedConst<'tcx> {
pub def: ty::WithOptConstParam<DefId>,
pub substs: SubstsRef<'tcx>,
- pub promoted: P,
}
-impl rustc_errors::IntoDiagnosticArg for Unevaluated<'_> {
+impl rustc_errors::IntoDiagnosticArg for UnevaluatedConst<'_> {
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
format!("{:?}", self).into_diagnostic_arg()
}
}
-impl<'tcx> Unevaluated<'tcx> {
- #[inline]
- pub fn shrink(self) -> Unevaluated<'tcx, ()> {
- debug_assert_eq!(self.promoted, None);
- Unevaluated { def: self.def, substs: self.substs, promoted: () }
- }
-}
-
-impl<'tcx> Unevaluated<'tcx, ()> {
+impl<'tcx> UnevaluatedConst<'tcx> {
#[inline]
- pub fn expand(self) -> Unevaluated<'tcx> {
- Unevaluated { def: self.def, substs: self.substs, promoted: None }
+ pub fn expand(self) -> mir::UnevaluatedConst<'tcx> {
+ mir::UnevaluatedConst { def: self.def, substs: self.substs, promoted: None }
}
}
-impl<'tcx, P: Default> Unevaluated<'tcx, P> {
+impl<'tcx> UnevaluatedConst<'tcx> {
#[inline]
- pub fn new(def: ty::WithOptConstParam<DefId>, substs: SubstsRef<'tcx>) -> Unevaluated<'tcx, P> {
- Unevaluated { def, substs, promoted: Default::default() }
+ pub fn new(
+ def: ty::WithOptConstParam<DefId>,
+ substs: SubstsRef<'tcx>,
+ ) -> UnevaluatedConst<'tcx> {
+ UnevaluatedConst { def, substs }
}
}
@@ -67,7 +62,7 @@ pub enum ConstKind<'tcx> {
/// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
/// variants when the code is monomorphic enough for that.
- Unevaluated(Unevaluated<'tcx, ()>),
+ Unevaluated(UnevaluatedConst<'tcx>),
/// Used to hold computed value.
Value(ty::ValTree<'tcx>),
@@ -114,7 +109,6 @@ 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(HashStable)]
pub enum InferConst<'tcx> {
/// Infer the value of the const.
Var(ty::ConstVid<'tcx>),
@@ -122,6 +116,15 @@ pub enum InferConst<'tcx> {
Fresh(u32),
}
+impl<CTX> HashStable<CTX> for InferConst<'_> {
+ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+ match self {
+ InferConst::Var(_) => panic!("const variables should not be hashed: {self:?}"),
+ InferConst::Fresh(i) => i.hash_stable(hcx, hasher),
+ }
+ }
+}
+
enum EvalMode {
Typeck,
Mir,
@@ -185,8 +188,6 @@ impl<'tcx> ConstKind<'tcx> {
if let ConstKind::Unevaluated(unevaluated) = self {
use crate::mir::interpret::ErrorHandled;
- assert_eq!(unevaluated.promoted, ());
-
// HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
// also does later, but we want to do it before checking for
// inference variables.
@@ -204,10 +205,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_and.needs_infer() {
- tcx.param_env(unevaluated.def.did).and(ty::Unevaluated {
+ tcx.param_env(unevaluated.def.did).and(ty::UnevaluatedConst {
def: unevaluated.def,
substs: InternalSubsts::identity_for_item(tcx, unevaluated.def.did),
- promoted: (),
})
} else {
param_env_and
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 0b497fa4a..3d7e2a083 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1,10 +1,10 @@
//! Type context book-keeping.
use crate::arena::Arena;
-use crate::dep_graph::{DepGraph, DepKind, DepKindStruct};
+use crate::dep_graph::{DepGraph, DepKindStruct};
use crate::hir::place::Place as HirPlace;
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
-use crate::lint::{struct_lint_level, LintLevelSource};
+use crate::lint::struct_lint_level;
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
use crate::middle::resolve_lifetime;
use crate::middle::stability;
@@ -15,7 +15,6 @@ use crate::mir::{
use crate::thir::Thir;
use crate::traits;
use crate::ty::query::{self, TyCtxtAt};
-use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
use crate::ty::{
self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
ClosureSizeProfileData, Const, ConstS, ConstVid, DefIdTree, ExistentialPredicate, FloatTy,
@@ -24,6 +23,7 @@ use crate::ty::{
RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy,
Visibility,
};
+use crate::ty::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef, UserSubsts};
use rustc_ast as ast;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -34,12 +34,16 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, RwLock, WorkerLocal};
+use rustc_data_structures::unord::UnordSet;
use rustc_data_structures::vec_map::VecMap;
-use rustc_errors::{DecorateLint, ErrorGuaranteed, LintDiagnosticBuilder, MultiSpan};
+use rustc_errors::{
+ DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
+};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
use rustc_hir::definitions::Definitions;
+use rustc_hir::hir_id::OwnerId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
@@ -53,7 +57,7 @@ use rustc_query_system::ich::StableHashingContext;
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use rustc_session::config::{CrateType, OutputFilenames};
use rustc_session::cstore::CrateStoreDyn;
-use rustc_session::lint::{Level, Lint};
+use rustc_session::lint::Lint;
use rustc_session::Limit;
use rustc_session::Session;
use rustc_span::def_id::{DefPathHash, StableCrateId};
@@ -76,7 +80,7 @@ use std::mem;
use std::ops::{Bound, Deref};
use std::sync::Arc;
-use super::{ImplPolarity, RvalueScopes};
+use super::{ImplPolarity, ResolverOutputs, RvalueScopes};
pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
/// Creates a new `OnDiskCache` instance from the serialized data in `data`.
@@ -195,9 +199,9 @@ impl<'tcx> CtxtInterners<'tcx> {
.intern(kind, |kind| {
let flags = super::flags::FlagComputation::for_kind(&kind);
- // It's impossible to hash inference regions (and will ICE), so we don't need to try to cache them.
+ // 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.
- let stable_hash = if flags.flags.intersects(TypeFlags::HAS_RE_INFER)
+ let stable_hash = if flags.flags.intersects(TypeFlags::NEEDS_INFER)
|| sess.opts.incremental.is_none()
{
Fingerprint::ZERO
@@ -288,7 +292,7 @@ pub struct CommonConsts<'tcx> {
}
pub struct LocalTableInContext<'a, V> {
- hir_owner: LocalDefId,
+ hir_owner: OwnerId,
data: &'a ItemLocalMap<V>,
}
@@ -300,7 +304,7 @@ pub struct LocalTableInContext<'a, V> {
/// would result in lookup errors, or worse, in silently wrong data being
/// stored/returned.
#[inline]
-fn validate_hir_id_for_typeck_results(hir_owner: LocalDefId, hir_id: hir::HirId) {
+fn validate_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
if hir_id.owner != hir_owner {
invalid_hir_id_for_typeck_results(hir_owner, hir_id);
}
@@ -308,7 +312,7 @@ fn validate_hir_id_for_typeck_results(hir_owner: LocalDefId, hir_id: hir::HirId)
#[cold]
#[inline(never)]
-fn invalid_hir_id_for_typeck_results(hir_owner: LocalDefId, hir_id: hir::HirId) {
+fn invalid_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: hir::HirId) {
ty::tls::with(|tcx| {
bug!(
"node {} with HirId::owner {:?} cannot be placed in TypeckResults with hir_owner {:?}",
@@ -344,7 +348,7 @@ impl<'a, V> ::std::ops::Index<hir::HirId> for LocalTableInContext<'a, V> {
}
pub struct LocalTableInContextMut<'a, V> {
- hir_owner: LocalDefId,
+ hir_owner: OwnerId,
data: &'a mut ItemLocalMap<V>,
}
@@ -416,7 +420,7 @@ pub struct GeneratorDiagnosticData<'tcx> {
#[derive(TyEncodable, TyDecodable, Debug, HashStable)]
pub struct TypeckResults<'tcx> {
/// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
- pub hir_owner: LocalDefId,
+ pub hir_owner: OwnerId,
/// Resolved definitions for `<T>::X` associated paths and
/// method calls, including those of overloaded operators.
@@ -528,19 +532,17 @@ pub struct TypeckResults<'tcx> {
/// This is used for warning unused imports. During type
/// checking, this `Lrc` should not be cloned: it must have a ref-count
/// of 1 so that we can insert things into the set mutably.
- pub used_trait_imports: Lrc<FxHashSet<LocalDefId>>,
+ pub used_trait_imports: Lrc<UnordSet<LocalDefId>>,
/// If any errors occurred while type-checking this body,
/// this field will be set to `Some(ErrorGuaranteed)`.
pub tainted_by_errors: Option<ErrorGuaranteed>,
/// All the opaque types that have hidden types set
- /// by this function. For return-position-impl-trait we also store the
- /// type here, so that mir-borrowck can figure out hidden types,
+ /// 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).
- /// For type-alias-impl-trait, this map is only used to prevent query cycles,
- /// so the hidden types are all `None`.
- pub concrete_opaque_types: VecMap<LocalDefId, Option<Ty<'tcx>>>,
+ pub concrete_opaque_types: VecMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
/// Tracks the minimum captures required for a closure;
/// see `MinCaptureInformationMap` for more details.
@@ -572,7 +574,7 @@ pub struct TypeckResults<'tcx> {
/// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions
/// by applying extended parameter rules.
- /// Details may be find in `rustc_typeck::check::rvalue_scopes`.
+ /// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`.
pub rvalue_scopes: RvalueScopes,
/// Stores the type, expression, span and optional scope span of all types
@@ -591,7 +593,7 @@ pub struct TypeckResults<'tcx> {
}
impl<'tcx> TypeckResults<'tcx> {
- pub fn new(hir_owner: LocalDefId) -> TypeckResults<'tcx> {
+ pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> {
TypeckResults {
hir_owner,
type_dependent_defs: Default::default(),
@@ -1066,10 +1068,9 @@ pub struct GlobalCtxt<'tcx> {
pub consts: CommonConsts<'tcx>,
definitions: RwLock<Definitions>,
- cstore: Box<CrateStoreDyn>,
/// Output of the resolver.
- pub(crate) untracked_resolutions: ty::ResolverOutputs,
+ pub(crate) untracked_resolutions: ty::ResolverGlobalCtxt,
untracked_resolver_for_lowering: Steal<ty::ResolverAstLowering>,
/// The entire crate as AST. This field serves as the input for the hir_crate query,
/// which lowers it from AST to HIR. It must not be read or used by anything else.
@@ -1083,7 +1084,7 @@ pub struct GlobalCtxt<'tcx> {
pub queries: &'tcx dyn query::QueryEngine<'tcx>,
pub query_caches: query::QueryCaches<'tcx>,
- query_kinds: &'tcx [DepKindStruct<'tcx>],
+ pub(crate) query_kinds: &'tcx [DepKindStruct<'tcx>],
// Internal caches for metadata decoding. No need to track deps on this.
pub ty_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
@@ -1232,10 +1233,7 @@ impl<'tcx> TyCtxt<'tcx> {
lint_store: Lrc<dyn Any + sync::Send + sync::Sync>,
arena: &'tcx WorkerLocal<Arena<'tcx>>,
hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>,
- definitions: Definitions,
- cstore: Box<CrateStoreDyn>,
- untracked_resolutions: ty::ResolverOutputs,
- untracked_resolver_for_lowering: ty::ResolverAstLowering,
+ resolver_outputs: ResolverOutputs,
krate: Lrc<ast::Crate>,
dep_graph: DepGraph,
on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
@@ -1244,6 +1242,11 @@ impl<'tcx> TyCtxt<'tcx> {
crate_name: &str,
output_filenames: OutputFilenames,
) -> GlobalCtxt<'tcx> {
+ let ResolverOutputs {
+ definitions,
+ global_ctxt: untracked_resolutions,
+ ast_lowering: untracked_resolver_for_lowering,
+ } = resolver_outputs;
let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| {
s.emit_fatal(err);
});
@@ -1252,7 +1255,7 @@ impl<'tcx> TyCtxt<'tcx> {
&interners,
s,
&definitions,
- &*cstore,
+ &*untracked_resolutions.cstore,
// This is only used to create a stable hashing context.
&untracked_resolutions.source_span,
);
@@ -1267,7 +1270,6 @@ impl<'tcx> TyCtxt<'tcx> {
interners,
dep_graph,
definitions: RwLock::new(definitions),
- cstore,
prof: s.prof.clone(),
types: common_types,
lifetimes: common_lifetimes,
@@ -1290,10 +1292,6 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
- pub(crate) fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct<'tcx> {
- &self.query_kinds[k as usize]
- }
-
/// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
#[track_caller]
pub fn ty_error(self) -> Ty<'tcx> {
@@ -1372,7 +1370,7 @@ impl<'tcx> TyCtxt<'tcx> {
if let Some(id) = id.as_local() {
self.definitions_untracked().def_key(id)
} else {
- self.cstore.def_key(id)
+ self.untracked_resolutions.cstore.def_key(id)
}
}
@@ -1386,7 +1384,7 @@ impl<'tcx> TyCtxt<'tcx> {
if let Some(id) = id.as_local() {
self.definitions_untracked().def_path(id)
} else {
- self.cstore.def_path(id)
+ self.untracked_resolutions.cstore.def_path(id)
}
}
@@ -1396,7 +1394,7 @@ impl<'tcx> TyCtxt<'tcx> {
if let Some(def_id) = def_id.as_local() {
self.definitions_untracked().def_path_hash(def_id)
} else {
- self.cstore.def_path_hash(def_id)
+ self.untracked_resolutions.cstore.def_path_hash(def_id)
}
}
@@ -1405,7 +1403,7 @@ impl<'tcx> TyCtxt<'tcx> {
if crate_num == LOCAL_CRATE {
self.sess.local_stable_crate_id()
} else {
- self.cstore.stable_crate_id(crate_num)
+ self.untracked_resolutions.cstore.stable_crate_id(crate_num)
}
}
@@ -1416,7 +1414,7 @@ impl<'tcx> TyCtxt<'tcx> {
if stable_crate_id == self.sess.local_stable_crate_id() {
LOCAL_CRATE
} else {
- self.cstore.stable_crate_id_to_crate_num(stable_crate_id)
+ self.untracked_resolutions.cstore.stable_crate_id_to_crate_num(stable_crate_id)
}
}
@@ -1435,8 +1433,9 @@ impl<'tcx> TyCtxt<'tcx> {
} else {
// If this is a DefPathHash from an upstream crate, let the CrateStore map
// it to a DefId.
- let cnum = self.cstore.stable_crate_id_to_crate_num(stable_crate_id);
- self.cstore.def_path_hash_to_def_id(cnum, hash)
+ let cstore = &*self.untracked_resolutions.cstore;
+ let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id);
+ cstore.def_path_hash_to_def_id(cnum, hash)
}
}
@@ -1448,7 +1447,7 @@ impl<'tcx> TyCtxt<'tcx> {
let (crate_name, stable_crate_id) = if def_id.is_local() {
(self.crate_name, self.sess.local_stable_crate_id())
} else {
- let cstore = &self.cstore;
+ let cstore = &*self.untracked_resolutions.cstore;
(cstore.crate_name(def_id.krate), cstore.stable_crate_id(def_id.krate))
};
@@ -1523,7 +1522,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Note that this is *untracked* and should only be used within the query
/// system if the result is otherwise tracked through queries
pub fn cstore_untracked(self) -> &'tcx CrateStoreDyn {
- &*self.cstore
+ &*self.untracked_resolutions.cstore
}
/// Note that this is *untracked* and should only be used within the query
@@ -1549,7 +1548,7 @@ impl<'tcx> TyCtxt<'tcx> {
let hcx = StableHashingContext::new(
self.sess,
&*definitions,
- &*self.cstore,
+ &*self.untracked_resolutions.cstore,
&self.untracked_resolutions.source_span,
);
f(hcx)
@@ -1725,7 +1724,7 @@ impl<'tcx> TyCtxt<'tcx> {
#[inline]
pub fn local_visibility(self, def_id: LocalDefId) -> Visibility {
- self.visibility(def_id.to_def_id()).expect_local()
+ self.visibility(def_id).expect_local()
}
}
@@ -2367,7 +2366,7 @@ impl<'tcx> TyCtxt<'tcx> {
st,
self.sess,
&self.definitions.read(),
- &*self.cstore,
+ &*self.untracked_resolutions.cstore,
// This is only used to create a stable hashing context.
&self.untracked_resolutions.source_span,
)
@@ -2812,44 +2811,6 @@ impl<'tcx> TyCtxt<'tcx> {
iter.intern_with(|xs| self.intern_bound_variable_kinds(xs))
}
- /// Walks upwards from `id` to find a node which might change lint levels with attributes.
- /// It stops at `bound` and just returns it if reached.
- pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId {
- let hir = self.hir();
- loop {
- if id == bound {
- return bound;
- }
-
- if hir.attrs(id).iter().any(|attr| Level::from_attr(attr).is_some()) {
- return id;
- }
- let next = hir.get_parent_node(id);
- if next == id {
- bug!("lint traversal reached the root of the crate");
- }
- id = next;
- }
- }
-
- pub fn lint_level_at_node(
- self,
- lint: &'static Lint,
- mut id: hir::HirId,
- ) -> (Level, LintLevelSource) {
- let sets = self.lint_levels(());
- loop {
- if let Some(pair) = sets.level_and_source(lint, id, self.sess) {
- return pair;
- }
- let next = self.hir().get_parent_node(id);
- if next == id {
- bug!("lint traversal reached the root of the crate");
- }
- id = next;
- }
- }
-
/// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`,
/// typically generated by `#[derive(LintDiagnostic)]`).
pub fn emit_spanned_lint(
@@ -2859,18 +2820,28 @@ impl<'tcx> TyCtxt<'tcx> {
span: impl Into<MultiSpan>,
decorator: impl for<'a> DecorateLint<'a, ()>,
) {
- self.struct_span_lint_hir(lint, hir_id, span, |diag| decorator.decorate_lint(diag))
+ self.struct_span_lint_hir(lint, hir_id, span, decorator.msg(), |diag| {
+ decorator.decorate_lint(diag)
+ })
}
+ /// Emit a lint at the appropriate level for a hir node, with an associated span.
+ ///
+ /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+ ///
+ /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
pub fn struct_span_lint_hir(
self,
lint: &'static Lint,
hir_id: HirId,
span: impl Into<MultiSpan>,
- decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+ msg: impl Into<DiagnosticMessage>,
+ decorate: impl for<'a, 'b> FnOnce(
+ &'b mut DiagnosticBuilder<'a, ()>,
+ ) -> &'b mut DiagnosticBuilder<'a, ()>,
) {
let (level, src) = self.lint_level_at_node(lint, hir_id);
- struct_lint_level(self.sess, lint, level, src, Some(span.into()), decorate);
+ struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg, decorate);
}
/// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically
@@ -2881,17 +2852,25 @@ impl<'tcx> TyCtxt<'tcx> {
id: HirId,
decorator: impl for<'a> DecorateLint<'a, ()>,
) {
- self.struct_lint_node(lint, id, |diag| decorator.decorate_lint(diag))
+ self.struct_lint_node(lint, id, decorator.msg(), |diag| decorator.decorate_lint(diag))
}
+ /// Emit a lint at the appropriate level for a hir node.
+ ///
+ /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+ ///
+ /// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
pub fn struct_lint_node(
self,
lint: &'static Lint,
id: HirId,
- decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+ msg: impl Into<DiagnosticMessage>,
+ decorate: impl for<'a, 'b> FnOnce(
+ &'b mut DiagnosticBuilder<'a, ()>,
+ ) -> &'b mut DiagnosticBuilder<'a, ()>,
) {
let (level, src) = self.lint_level_at_node(lint, id);
- struct_lint_level(self.sess, lint, level, src, None, decorate);
+ struct_lint_level(self.sess, lint, level, src, None, msg, decorate);
}
pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate]> {
@@ -2906,7 +2885,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| {
+ self.is_late_bound_map(id.owner.def_id).map_or(false, |set| {
let def_id = self.hir().local_def_id(id);
set.contains(&def_id)
})
@@ -2977,6 +2956,21 @@ impl<'tcx> TyCtxtAt<'tcx> {
}
}
+/// Parameter attributes that can only be determined by examining the body of a function instead
+/// of just its signature.
+///
+/// These can be useful for optimization purposes when a function is directly called. We compute
+/// them and store them into the crate metadata so that downstream crates can make use of them.
+///
+/// Right now, we only have `read_only`, but `no_capture` and `no_alias` might be useful in the
+/// future.
+#[derive(Clone, Copy, PartialEq, Debug, Default, TyDecodable, TyEncodable, HashStable)]
+pub struct DeducedParamAttrs {
+ /// The parameter is marked immutable in the function and contains no `UnsafeCell` (i.e. its
+ /// type is freeze).
+ pub read_only: bool,
+}
+
// We are comparing types with different invariant lifetimes, so `ptr::eq`
// won't work for us.
fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 855917fb8..b8fd01e6a 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -511,3 +511,11 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
c.super_visit_with(self)
}
}
+
+#[derive(Diagnostic)]
+#[diag(borrowck_const_not_used_in_type_alias)]
+pub(super) struct ConstNotUsedTraitAlias {
+ pub ct: String,
+ #[primary_span]
+ pub span: Span,
+}
diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs
index 3226950e7..ffdac93bc 100644
--- a/compiler/rustc_middle/src/ty/erase_regions.rs
+++ b/compiler/rustc_middle/src/ty/erase_regions.rs
@@ -1,4 +1,3 @@
-use crate::mir;
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use crate::ty::visit::TypeVisitable;
use crate::ty::{self, Ty, TyCtxt, TypeFlags};
@@ -67,8 +66,4 @@ impl<'tcx> TypeFolder<'tcx> for RegionEraserVisitor<'tcx> {
_ => self.tcx.lifetimes.re_erased,
}
}
-
- fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
- c.super_fold_with(self)
- }
}
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 01e1e97b2..4e6cdb786 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -861,7 +861,7 @@ fn foo(&self) -> Self::T { String::new() }
// When `body_owner` is an `impl` or `trait` item, look in its associated types for
// `expected` and point at it.
let parent_id = self.hir().get_parent_item(hir_id);
- let item = self.hir().find_by_def_id(parent_id);
+ let item = self.hir().find_by_def_id(parent_id.def_id);
debug!("expected_projection parent item {:?}", item);
match item {
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => {
@@ -872,9 +872,9 @@ fn foo(&self) -> Self::T { String::new() }
// FIXME: account for returning some type in a trait fn impl that has
// an assoc type as a return type (#72076).
if let hir::Defaultness::Default { has_value: true } =
- self.impl_defaultness(item.id.def_id)
+ self.impl_defaultness(item.id.owner_id)
{
- if self.type_of(item.id.def_id) == found {
+ if self.type_of(item.id.owner_id) == found {
diag.span_label(
item.span,
"associated type defaults can't be assumed inside the \
@@ -894,7 +894,7 @@ fn foo(&self) -> Self::T { String::new() }
})) => {
for item in &items[..] {
if let hir::AssocItemKind::Type = item.kind {
- if self.type_of(item.id.def_id) == found {
+ if self.type_of(item.id.owner_id) == found {
diag.span_label(item.span, "expected this associated type");
return true;
}
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 8d019a3ba..3be0bc4de 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -132,7 +132,7 @@ pub fn simplify_type<'tcx>(
// don't unify with anything else as long as they are fully normalized.
//
// We will have to be careful with lazy normalization here.
- TreatParams::AsPlaceholder if !ty.has_infer_types_or_consts() => {
+ TreatParams::AsPlaceholder if !ty.has_non_region_infer() => {
debug!("treating `{}` as a placeholder", ty);
Some(PlaceholderSimplifiedType)
}
@@ -384,14 +384,7 @@ impl DeepRejectCtxt {
// they might unify with any value.
ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => true,
ty::ConstKind::Value(obl) => match k {
- ty::ConstKind::Value(imp) => {
- // FIXME(valtrees): Once we have valtrees, we can just
- // compare them directly here.
- match (obl.try_to_scalar_int(), imp.try_to_scalar_int()) {
- (Some(obl), Some(imp)) => obl == imp,
- _ => true,
- }
- }
+ ty::ConstKind::Value(imp) => obl == imp,
_ => true,
},
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 98b8a7386..7201737be 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -34,12 +34,6 @@ impl FlagComputation {
result.flags
}
- pub fn for_unevaluated_const(uv: ty::Unevaluated<'_>) -> TypeFlags {
- let mut result = FlagComputation::new();
- result.add_unevaluated_const(uv);
- result.flags
- }
-
fn add_flags(&mut self, flags: TypeFlags) {
self.flags = self.flags | flags;
}
@@ -256,7 +250,7 @@ impl FlagComputation {
self.add_substs(substs);
}
ty::PredicateKind::ConstEvaluatable(uv) => {
- self.add_unevaluated_const(uv);
+ self.add_const(uv);
}
ty::PredicateKind::ConstEquate(expected, found) => {
self.add_const(expected);
@@ -289,7 +283,10 @@ impl FlagComputation {
fn add_const(&mut self, c: ty::Const<'_>) {
self.add_ty(c.ty());
match c.kind() {
- ty::ConstKind::Unevaluated(unevaluated) => self.add_unevaluated_const(unevaluated),
+ ty::ConstKind::Unevaluated(uv) => {
+ self.add_substs(uv.substs);
+ self.add_flags(TypeFlags::HAS_CT_PROJECTION);
+ }
ty::ConstKind::Infer(infer) => {
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
match infer {
@@ -313,11 +310,6 @@ impl FlagComputation {
}
}
- fn add_unevaluated_const<P>(&mut self, ct: ty::Unevaluated<'_, P>) {
- self.add_substs(ct.substs);
- self.add_flags(TypeFlags::HAS_CT_PROJECTION);
- }
-
fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
self.add_substs(projection.substs);
match projection.term.unpack() {
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index cac95e14a..54f1499eb 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -13,8 +13,7 @@
//!
//! There are three groups of traits involved in each traversal.
//! - `TypeFoldable`. This is implemented once for many types, including:
-//! - Types of interest, for which the the methods delegate to the
-//! folder.
+//! - 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,
@@ -43,7 +42,6 @@
//! - ty.super_fold_with(folder)
//! - u.fold_with(folder)
//! ```
-use crate::mir;
use crate::ty::{self, Binder, BoundTy, Ty, TyCtxt, TypeVisitable};
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::def_id::DefId;
@@ -128,17 +126,9 @@ pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> {
c.super_fold_with(self)
}
- fn fold_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ty::Unevaluated<'tcx> {
- uv.super_fold_with(self)
- }
-
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
p.super_fold_with(self)
}
-
- fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
- bug!("most type folders should not be folding MIR datastructures: {:?}", c)
- }
}
/// This trait is implemented for every folding traversal. There is a fold
@@ -172,26 +162,12 @@ pub trait FallibleTypeFolder<'tcx>: Sized {
c.try_super_fold_with(self)
}
- fn try_fold_unevaluated(
- &mut self,
- c: ty::Unevaluated<'tcx>,
- ) -> Result<ty::Unevaluated<'tcx>, Self::Error> {
- c.try_super_fold_with(self)
- }
-
fn try_fold_predicate(
&mut self,
p: ty::Predicate<'tcx>,
) -> Result<ty::Predicate<'tcx>, Self::Error> {
p.try_super_fold_with(self)
}
-
- fn try_fold_mir_const(
- &mut self,
- c: mir::ConstantKind<'tcx>,
- ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
- bug!("most type folders should not be folding MIR datastructures: {:?}", c)
- }
}
// This blanket implementation of the fallible trait for infallible folders
@@ -225,23 +201,9 @@ where
Ok(self.fold_const(c))
}
- fn try_fold_unevaluated(
- &mut self,
- c: ty::Unevaluated<'tcx>,
- ) -> Result<ty::Unevaluated<'tcx>, !> {
- Ok(self.fold_unevaluated(c))
- }
-
fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result<ty::Predicate<'tcx>, !> {
Ok(self.fold_predicate(p))
}
-
- fn try_fold_mir_const(
- &mut self,
- c: mir::ConstantKind<'tcx>,
- ) -> Result<mir::ConstantKind<'tcx>, !> {
- Ok(self.fold_mir_const(c))
- }
}
///////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 0c8bdde9c..19754d145 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -1,6 +1,5 @@
use crate::ty;
-use crate::ty::subst::{Subst, SubstsRef};
-use crate::ty::EarlyBinder;
+use crate::ty::{EarlyBinder, SubstsRef};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
deleted file mode 100644
index c4ad698ba..000000000
--- a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
+++ /dev/null
@@ -1,145 +0,0 @@
-use crate::ty::context::TyCtxt;
-use crate::ty::{DefId, DefIdTree};
-use rustc_span::def_id::CRATE_DEF_ID;
-use smallvec::SmallVec;
-use std::mem;
-
-use DefIdForest::*;
-
-/// Represents a forest of `DefId`s closed under the ancestor relation. That is,
-/// if a `DefId` representing a module is contained in the forest then all
-/// `DefId`s defined in that module or submodules are also implicitly contained
-/// in the forest.
-///
-/// This is used to represent a set of modules in which a type is visibly
-/// uninhabited.
-///
-/// We store the minimal set of `DefId`s required to represent the whole set. If A and B are
-/// `DefId`s in the `DefIdForest`, and A is a parent of B, then only A will be stored. When this is
-/// used with `type_uninhabited_from`, there will very rarely be more than one `DefId` stored.
-#[derive(Copy, Clone, HashStable, Debug)]
-pub enum DefIdForest<'a> {
- Empty,
- Single(DefId),
- /// This variant is very rare.
- /// Invariant: >1 elements
- Multiple(&'a [DefId]),
-}
-
-/// Tests whether a slice of roots contains a given DefId.
-#[inline]
-fn slice_contains<'tcx>(tcx: TyCtxt<'tcx>, slice: &[DefId], id: DefId) -> bool {
- slice.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
-}
-
-impl<'tcx> DefIdForest<'tcx> {
- /// Creates an empty forest.
- pub fn empty() -> DefIdForest<'tcx> {
- DefIdForest::Empty
- }
-
- /// Creates a forest consisting of a single tree representing the entire
- /// crate.
- #[inline]
- pub fn full() -> DefIdForest<'tcx> {
- DefIdForest::from_id(CRATE_DEF_ID.to_def_id())
- }
-
- /// Creates a forest containing a `DefId` and all its descendants.
- pub fn from_id(id: DefId) -> DefIdForest<'tcx> {
- DefIdForest::Single(id)
- }
-
- fn as_slice(&self) -> &[DefId] {
- match self {
- Empty => &[],
- Single(id) => std::slice::from_ref(id),
- Multiple(root_ids) => root_ids,
- }
- }
-
- // Only allocates in the rare `Multiple` case.
- fn from_vec(tcx: TyCtxt<'tcx>, root_ids: SmallVec<[DefId; 1]>) -> DefIdForest<'tcx> {
- match &root_ids[..] {
- [] => Empty,
- [id] => Single(*id),
- _ => DefIdForest::Multiple(tcx.arena.alloc_from_iter(root_ids)),
- }
- }
-
- /// Tests whether the forest is empty.
- pub fn is_empty(&self) -> bool {
- match self {
- Empty => true,
- Single(..) | Multiple(..) => false,
- }
- }
-
- /// Iterate over the set of roots.
- fn iter(&self) -> impl Iterator<Item = DefId> + '_ {
- self.as_slice().iter().copied()
- }
-
- /// Tests whether the forest contains a given DefId.
- pub fn contains(&self, tcx: TyCtxt<'tcx>, id: DefId) -> bool {
- slice_contains(tcx, self.as_slice(), id)
- }
-
- /// Calculate the intersection of a collection of forests.
- pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest<'tcx>
- where
- I: IntoIterator<Item = DefIdForest<'tcx>>,
- {
- let mut iter = iter.into_iter();
- let mut ret: SmallVec<[_; 1]> = if let Some(first) = iter.next() {
- SmallVec::from_slice(first.as_slice())
- } else {
- return DefIdForest::full();
- };
-
- let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
- for next_forest in iter {
- // No need to continue if the intersection is already empty.
- if ret.is_empty() || next_forest.is_empty() {
- return DefIdForest::empty();
- }
-
- // We keep the elements in `ret` that are also in `next_forest`.
- next_ret.extend(ret.iter().copied().filter(|&id| next_forest.contains(tcx, id)));
- // We keep the elements in `next_forest` that are also in `ret`.
- next_ret.extend(next_forest.iter().filter(|&id| slice_contains(tcx, &ret, id)));
-
- mem::swap(&mut next_ret, &mut ret);
- next_ret.clear();
- }
- DefIdForest::from_vec(tcx, ret)
- }
-
- /// Calculate the union of a collection of forests.
- pub fn union<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest<'tcx>
- where
- I: IntoIterator<Item = DefIdForest<'tcx>>,
- {
- let mut ret: SmallVec<[_; 1]> = SmallVec::new();
- let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
- for next_forest in iter {
- // Union with the empty set is a no-op.
- if next_forest.is_empty() {
- continue;
- }
-
- // We add everything in `ret` that is not in `next_forest`.
- next_ret.extend(ret.iter().copied().filter(|&id| !next_forest.contains(tcx, id)));
- // We add everything in `next_forest` that we haven't added yet.
- for id in next_forest.iter() {
- if !slice_contains(tcx, &next_ret, id) {
- next_ret.push(id);
- }
- }
-
- mem::swap(&mut next_ret, &mut ret);
- next_ret.clear();
- }
- DefIdForest::from_vec(tcx, ret)
- }
-}
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
new file mode 100644
index 000000000..b7aa45572
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
@@ -0,0 +1,204 @@
+use crate::ty::context::TyCtxt;
+use crate::ty::{self, DefId, DefIdTree, ParamEnv, Ty};
+
+/// Represents whether some type is inhabited in a given context.
+/// Examples of uninhabited types are `!`, `enum Void {}`, or a struct
+/// containing either of those types.
+/// A type's inhabitedness may depend on the `ParamEnv` as well as what types
+/// are visible in the current module.
+#[derive(Clone, Copy, Debug, PartialEq, HashStable)]
+pub enum InhabitedPredicate<'tcx> {
+ /// Inhabited
+ True,
+ /// Uninhabited
+ False,
+ /// Uninhabited when a const value is non-zero. This occurs when there is an
+ /// array of uninhabited items, but the array is inhabited if it is empty.
+ ConstIsZero(ty::Const<'tcx>),
+ /// Uninhabited if within a certain module. This occurs when an uninhabited
+ /// type has restricted visibility.
+ NotInModule(DefId),
+ /// Inhabited if some generic type is inhabited.
+ /// These are replaced by calling [`Self::subst`].
+ GenericType(Ty<'tcx>),
+ /// A AND B
+ And(&'tcx [InhabitedPredicate<'tcx>; 2]),
+ /// A OR B
+ Or(&'tcx [InhabitedPredicate<'tcx>; 2]),
+}
+
+impl<'tcx> InhabitedPredicate<'tcx> {
+ /// Returns true if the corresponding type is inhabited in the given
+ /// `ParamEnv` and module
+ pub fn apply(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, module_def_id: DefId) -> bool {
+ let Ok(result) = self
+ .apply_inner::<!>(tcx, param_env, &|id| Ok(tcx.is_descendant_of(module_def_id, id)));
+ result
+ }
+
+ /// Same as `apply`, but returns `None` if self contains a module predicate
+ pub fn apply_any_module(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
+ self.apply_inner(tcx, param_env, &|_| Err(())).ok()
+ }
+
+ fn apply_inner<E>(
+ self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ in_module: &impl Fn(DefId) -> Result<bool, E>,
+ ) -> Result<bool, E> {
+ match self {
+ Self::False => Ok(false),
+ Self::True => Ok(true),
+ Self::ConstIsZero(const_) => match const_.try_eval_usize(tcx, param_env) {
+ None | Some(0) => Ok(true),
+ Some(1..) => Ok(false),
+ },
+ Self::NotInModule(id) => in_module(id).map(|in_mod| !in_mod),
+ Self::GenericType(_) => Ok(true),
+ Self::And([a, b]) => try_and(a, b, |x| x.apply_inner(tcx, param_env, in_module)),
+ Self::Or([a, b]) => try_or(a, b, |x| x.apply_inner(tcx, param_env, in_module)),
+ }
+ }
+
+ pub fn and(self, tcx: TyCtxt<'tcx>, other: Self) -> Self {
+ self.reduce_and(tcx, other).unwrap_or_else(|| Self::And(tcx.arena.alloc([self, other])))
+ }
+
+ pub fn or(self, tcx: TyCtxt<'tcx>, other: Self) -> Self {
+ self.reduce_or(tcx, other).unwrap_or_else(|| Self::Or(tcx.arena.alloc([self, other])))
+ }
+
+ pub fn all(tcx: TyCtxt<'tcx>, iter: impl IntoIterator<Item = Self>) -> Self {
+ let mut result = Self::True;
+ for pred in iter {
+ if matches!(pred, Self::False) {
+ return Self::False;
+ }
+ result = result.and(tcx, pred);
+ }
+ result
+ }
+
+ pub fn any(tcx: TyCtxt<'tcx>, iter: impl IntoIterator<Item = Self>) -> Self {
+ let mut result = Self::False;
+ for pred in iter {
+ if matches!(pred, Self::True) {
+ return Self::True;
+ }
+ result = result.or(tcx, pred);
+ }
+ result
+ }
+
+ fn reduce_and(self, tcx: TyCtxt<'tcx>, other: Self) -> Option<Self> {
+ match (self, other) {
+ (Self::True, a) | (a, Self::True) => Some(a),
+ (Self::False, _) | (_, Self::False) => Some(Self::False),
+ (Self::ConstIsZero(a), Self::ConstIsZero(b)) if a == b => Some(Self::ConstIsZero(a)),
+ (Self::NotInModule(a), Self::NotInModule(b)) if a == b => Some(Self::NotInModule(a)),
+ (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(a, b) => {
+ Some(Self::NotInModule(b))
+ }
+ (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(b, a) => {
+ Some(Self::NotInModule(a))
+ }
+ (Self::GenericType(a), Self::GenericType(b)) if a == b => Some(Self::GenericType(a)),
+ (Self::And(&[a, b]), c) | (c, Self::And(&[a, b])) => {
+ if let Some(ac) = a.reduce_and(tcx, c) {
+ Some(ac.and(tcx, b))
+ } else if let Some(bc) = b.reduce_and(tcx, c) {
+ Some(Self::And(tcx.arena.alloc([a, bc])))
+ } else {
+ None
+ }
+ }
+ _ => None,
+ }
+ }
+
+ fn reduce_or(self, tcx: TyCtxt<'tcx>, other: Self) -> Option<Self> {
+ match (self, other) {
+ (Self::True, _) | (_, Self::True) => Some(Self::True),
+ (Self::False, a) | (a, Self::False) => Some(a),
+ (Self::ConstIsZero(a), Self::ConstIsZero(b)) if a == b => Some(Self::ConstIsZero(a)),
+ (Self::NotInModule(a), Self::NotInModule(b)) if a == b => Some(Self::NotInModule(a)),
+ (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(a, b) => {
+ Some(Self::NotInModule(a))
+ }
+ (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(b, a) => {
+ Some(Self::NotInModule(b))
+ }
+ (Self::GenericType(a), Self::GenericType(b)) if a == b => Some(Self::GenericType(a)),
+ (Self::Or(&[a, b]), c) | (c, Self::Or(&[a, b])) => {
+ if let Some(ac) = a.reduce_or(tcx, c) {
+ Some(ac.or(tcx, b))
+ } else if let Some(bc) = b.reduce_or(tcx, c) {
+ Some(Self::Or(tcx.arena.alloc([a, bc])))
+ } else {
+ None
+ }
+ }
+ _ => None,
+ }
+ }
+
+ /// Replaces generic types with its corresponding predicate
+ pub fn subst(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Self {
+ self.subst_opt(tcx, substs).unwrap_or(self)
+ }
+
+ fn subst_opt(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Option<Self> {
+ match self {
+ Self::ConstIsZero(c) => {
+ let c = ty::EarlyBinder(c).subst(tcx, substs);
+ let pred = match c.kind().try_to_machine_usize(tcx) {
+ Some(0) => Self::True,
+ Some(1..) => Self::False,
+ None => Self::ConstIsZero(c),
+ };
+ Some(pred)
+ }
+ Self::GenericType(t) => {
+ Some(ty::EarlyBinder(t).subst(tcx, substs).inhabited_predicate(tcx))
+ }
+ Self::And(&[a, b]) => match a.subst_opt(tcx, substs) {
+ None => b.subst_opt(tcx, substs).map(|b| a.and(tcx, b)),
+ Some(InhabitedPredicate::False) => Some(InhabitedPredicate::False),
+ Some(a) => Some(a.and(tcx, b.subst_opt(tcx, substs).unwrap_or(b))),
+ },
+ Self::Or(&[a, b]) => match a.subst_opt(tcx, substs) {
+ None => b.subst_opt(tcx, substs).map(|b| a.or(tcx, b)),
+ Some(InhabitedPredicate::True) => Some(InhabitedPredicate::True),
+ Some(a) => Some(a.or(tcx, b.subst_opt(tcx, substs).unwrap_or(b))),
+ },
+ _ => None,
+ }
+ }
+}
+
+// this is basically like `f(a)? && f(b)?` but different in the case of
+// `Ok(false) && Err(_) -> Ok(false)`
+fn try_and<T, E>(a: T, b: T, f: impl Fn(T) -> Result<bool, E>) -> Result<bool, E> {
+ let a = f(a);
+ if matches!(a, Ok(false)) {
+ return Ok(false);
+ }
+ match (a, f(b)) {
+ (_, Ok(false)) | (Ok(false), _) => Ok(false),
+ (Ok(true), Ok(true)) => Ok(true),
+ (Err(e), _) | (_, Err(e)) => Err(e),
+ }
+}
+
+fn try_or<T, E>(a: T, b: T, f: impl Fn(T) -> Result<bool, E>) -> Result<bool, E> {
+ let a = f(a);
+ if matches!(a, Ok(true)) {
+ return Ok(true);
+ }
+ match (a, f(b)) {
+ (_, Ok(true)) | (Ok(true), _) => Ok(true),
+ (Ok(false), Ok(false)) => Ok(false),
+ (Err(e), _) | (_, Err(e)) => Err(e),
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index aaa66deb2..279a728ea 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -1,57 +1,60 @@
-pub use self::def_id_forest::DefIdForest;
+//! This module contains logic for determining whether a type is inhabited or
+//! uninhabited. The [`InhabitedPredicate`] type captures the minimum
+//! information needed to determine whether a type is inhabited given a
+//! `ParamEnv` and module ID.
+//!
+//! # Example
+//! ```rust
+//! enum Void {}
+//! mod a {
+//! pub mod b {
+//! pub struct SecretlyUninhabited {
+//! _priv: !,
+//! }
+//! }
+//! }
+//!
+//! mod c {
+//! pub struct AlsoSecretlyUninhabited {
+//! _priv: Void,
+//! }
+//! mod d {
+//! }
+//! }
+//!
+//! struct Foo {
+//! x: a::b::SecretlyUninhabited,
+//! y: c::AlsoSecretlyUninhabited,
+//! }
+//! ```
+//! In this code, the type `Foo` will only be visibly uninhabited inside the
+//! modules `b`, `c` and `d`. Calling `uninhabited_predicate` on `Foo` will
+//! return `NotInModule(b) AND NotInModule(c)`.
+//!
+//! We need this information for pattern-matching on `Foo` or types that contain
+//! `Foo`.
+//!
+//! # Example
+//! ```rust
+//! let foo_result: Result<T, Foo> = ... ;
+//! let Ok(t) = foo_result;
+//! ```
+//! This code should only compile in modules where the uninhabitedness of `Foo`
+//! is visible.
-use crate::ty;
use crate::ty::context::TyCtxt;
-use crate::ty::{AdtDef, FieldDef, Ty, VariantDef};
-use crate::ty::{AdtKind, Visibility};
-use crate::ty::{DefId, SubstsRef};
+use crate::ty::{self, DefId, Ty, VariantDef, Visibility};
use rustc_type_ir::sty::TyKind::*;
-mod def_id_forest;
+pub mod inhabited_predicate;
-// The methods in this module calculate `DefIdForest`s of modules in which an
-// `AdtDef`/`VariantDef`/`FieldDef` is visibly uninhabited.
-//
-// # Example
-// ```rust
-// enum Void {}
-// mod a {
-// pub mod b {
-// pub struct SecretlyUninhabited {
-// _priv: !,
-// }
-// }
-// }
-//
-// mod c {
-// pub struct AlsoSecretlyUninhabited {
-// _priv: Void,
-// }
-// mod d {
-// }
-// }
-//
-// struct Foo {
-// x: a::b::SecretlyUninhabited,
-// y: c::AlsoSecretlyUninhabited,
-// }
-// ```
-// In this code, the type `Foo` will only be visibly uninhabited inside the
-// modules `b`, `c` and `d`. Calling `uninhabited_from` on `Foo` or its `AdtDef` will
-// return the forest of modules {`b`, `c`->`d`} (represented in a `DefIdForest` by the
-// set {`b`, `c`}).
-//
-// We need this information for pattern-matching on `Foo` or types that contain
-// `Foo`.
-//
-// # Example
-// ```rust
-// let foo_result: Result<T, Foo> = ... ;
-// let Ok(t) = foo_result;
-// ```
-// This code should only compile in modules where the uninhabitedness of `Foo` is
-// visible.
+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 };
+}
impl<'tcx> TyCtxt<'tcx> {
/// Checks whether a type is visibly uninhabited from a particular module.
@@ -100,131 +103,92 @@ impl<'tcx> TyCtxt<'tcx> {
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
- // To check whether this type is uninhabited at all (not just from the
- // given node), you could check whether the forest is empty.
- // ```
- // forest.is_empty()
- // ```
- ty.uninhabited_from(self, param_env).contains(self, module)
+ !ty.inhabited_predicate(self).apply(self, param_env, module)
}
}
-impl<'tcx> AdtDef<'tcx> {
- /// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited.
- fn uninhabited_from(
- self,
- tcx: TyCtxt<'tcx>,
- substs: SubstsRef<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ) -> DefIdForest<'tcx> {
- // Non-exhaustive ADTs from other crates are always considered inhabited.
- if self.is_variant_list_non_exhaustive() && !self.did().is_local() {
- DefIdForest::empty()
- } else {
- DefIdForest::intersection(
- tcx,
- self.variants()
- .iter()
- .map(|v| v.uninhabited_from(tcx, substs, self.adt_kind(), param_env)),
- )
+/// Returns an `InhabitedPredicate` that is generic over type parameters and
+/// requires calling [`InhabitedPredicate::subst`]
+fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> {
+ if let Some(def_id) = def_id.as_local() {
+ if matches!(tcx.representability(def_id), ty::Representability::Infinite) {
+ return InhabitedPredicate::True;
}
}
+ let adt = tcx.adt_def(def_id);
+ InhabitedPredicate::any(
+ tcx,
+ adt.variants().iter().map(|variant| variant.inhabited_predicate(tcx, adt)),
+ )
}
impl<'tcx> VariantDef {
/// Calculates the forest of `DefId`s from which this variant is visibly uninhabited.
- pub fn uninhabited_from(
+ pub fn inhabited_predicate(
&self,
tcx: TyCtxt<'tcx>,
- substs: SubstsRef<'tcx>,
- adt_kind: AdtKind,
- param_env: ty::ParamEnv<'tcx>,
- ) -> DefIdForest<'tcx> {
- let is_enum = match adt_kind {
- // For now, `union`s are never considered uninhabited.
- // The precise semantics of inhabitedness with respect to unions is currently undecided.
- AdtKind::Union => return DefIdForest::empty(),
- AdtKind::Enum => true,
- AdtKind::Struct => false,
- };
- // Non-exhaustive variants from other crates are always considered inhabited.
+ adt: ty::AdtDef<'_>,
+ ) -> InhabitedPredicate<'tcx> {
+ debug_assert!(!adt.is_union());
if self.is_field_list_non_exhaustive() && !self.def_id.is_local() {
- DefIdForest::empty()
- } else {
- DefIdForest::union(
- tcx,
- self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum, param_env)),
- )
+ // Non-exhaustive variants from other crates are always considered inhabited.
+ return InhabitedPredicate::True;
}
- }
-}
-
-impl<'tcx> FieldDef {
- /// Calculates the forest of `DefId`s from which this field is visibly uninhabited.
- fn uninhabited_from(
- &self,
- tcx: TyCtxt<'tcx>,
- substs: SubstsRef<'tcx>,
- is_enum: bool,
- param_env: ty::ParamEnv<'tcx>,
- ) -> DefIdForest<'tcx> {
- let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx, param_env);
- if is_enum {
- data_uninhabitedness()
- } else {
- match self.vis {
- Visibility::Restricted(from) => {
- let forest = DefIdForest::from_id(from);
- let iter = Some(forest).into_iter().chain(Some(data_uninhabitedness()));
- DefIdForest::intersection(tcx, iter)
+ InhabitedPredicate::all(
+ tcx,
+ self.fields.iter().map(|field| {
+ let pred = tcx.type_of(field.did).inhabited_predicate(tcx);
+ if adt.is_enum() {
+ return pred;
}
- Visibility::Public => data_uninhabitedness(),
- }
- }
+ match field.vis {
+ Visibility::Public => pred,
+ Visibility::Restricted(from) => {
+ pred.or(tcx, InhabitedPredicate::NotInModule(from))
+ }
+ }
+ }),
+ )
}
}
impl<'tcx> Ty<'tcx> {
- /// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
- fn uninhabited_from(
- self,
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ) -> DefIdForest<'tcx> {
- tcx.type_uninhabited_from(param_env.and(self))
+ pub fn inhabited_predicate(self, tcx: TyCtxt<'tcx>) -> InhabitedPredicate<'tcx> {
+ match self.kind() {
+ // For now, union`s are always considered inhabited
+ Adt(adt, _) if adt.is_union() => InhabitedPredicate::True,
+ // Non-exhaustive ADTs from other crates are always considered inhabited
+ Adt(adt, _) if adt.is_variant_list_non_exhaustive() && !adt.did().is_local() => {
+ InhabitedPredicate::True
+ }
+ Never => InhabitedPredicate::False,
+ Param(_) | Projection(_) => InhabitedPredicate::GenericType(self),
+ Tuple(tys) if tys.is_empty() => InhabitedPredicate::True,
+ // use a query for more complex cases
+ Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self),
+ // references and other types are inhabited
+ _ => InhabitedPredicate::True,
+ }
}
}
-// Query provider for `type_uninhabited_from`.
-pub(crate) fn type_uninhabited_from<'tcx>(
- tcx: TyCtxt<'tcx>,
- key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
-) -> DefIdForest<'tcx> {
- let ty = key.value;
- let param_env = key.param_env;
+/// N.B. this query should only be called through `Ty::inhabited_predicate`
+fn inhabited_predicate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InhabitedPredicate<'tcx> {
match *ty.kind() {
- Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env),
+ Adt(adt, substs) => tcx.inhabited_predicate_adt(adt.did()).subst(tcx, substs),
- Never => DefIdForest::full(),
-
- Tuple(ref tys) => {
- DefIdForest::union(tcx, tys.iter().map(|ty| ty.uninhabited_from(tcx, param_env)))
+ Tuple(tys) => {
+ InhabitedPredicate::all(tcx, tys.iter().map(|ty| ty.inhabited_predicate(tcx)))
}
- Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
- Some(0) | None => DefIdForest::empty(),
- // If the array is definitely non-empty, it's uninhabited if
- // the type of its elements is uninhabited.
- Some(1..) => ty.uninhabited_from(tcx, param_env),
+ // If we can evaluate the array length before having a `ParamEnv`, then
+ // we can simplify the predicate. This is an optimization.
+ Array(ty, len) => match len.kind().try_to_machine_usize(tcx) {
+ Some(0) => InhabitedPredicate::True,
+ Some(1..) => ty.inhabited_predicate(tcx),
+ None => ty.inhabited_predicate(tcx).or(tcx, InhabitedPredicate::ConstIsZero(len)),
},
- // References to uninitialised memory are valid for any type, including
- // uninhabited types, in unsafe code, so we treat all references as
- // inhabited.
- // The precise semantics of inhabitedness with respect to references is currently
- // undecided.
- Ref(..) => DefIdForest::empty(),
-
- _ => DefIdForest::empty(),
+ _ => bug!("unexpected TyKind, use `Ty::inhabited_predicate`"),
}
}
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 9afd66207..6c1414f7b 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -1,9 +1,7 @@
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::ty::print::{FmtPrinter, Printer};
-use crate::ty::subst::{InternalSubsts, Subst};
-use crate::ty::{
- self, EarlyBinder, SubstsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitable,
-};
+use crate::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitable};
+use crate::ty::{EarlyBinder, InternalSubsts, SubstsRef};
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::Namespace;
use rustc_hir::def_id::{CrateNum, DefId};
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 042eeec3f..3312f44c6 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1,41 +1,23 @@
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
use crate::ty::normalize_erasing_regions::NormalizationError;
-use crate::ty::subst::Subst;
-use crate::ty::{
- self, layout_sanity_check::sanity_check_layout, subst::SubstsRef, EarlyBinder, ReprOptions, Ty,
- TyCtxt, TypeVisitable,
-};
+use crate::ty::{self, ReprOptions, Ty, TyCtxt, TypeVisitable};
use rustc_ast as ast;
use rustc_attr as attr;
+use rustc_errors::{DiagnosticBuilder, Handler, IntoDiagnostic};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::LangItem;
-use rustc_index::bit_set::BitSet;
-use rustc_index::vec::{Idx, IndexVec};
-use rustc_session::{config::OptLevel, DataTypeKind, FieldInfo, SizeKind, VariantInfo};
-use rustc_span::symbol::Symbol;
+use rustc_index::vec::Idx;
+use rustc_session::config::OptLevel;
use rustc_span::{Span, DUMMY_SP};
-use rustc_target::abi::call::{
- ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
-};
+use rustc_target::abi::call::FnAbi;
use rustc_target::abi::*;
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
-use std::cmp::{self, Ordering};
+use std::cmp::{self};
use std::fmt;
-use std::iter;
use std::num::NonZeroUsize;
use std::ops::Bound;
-use rand::{seq::SliceRandom, SeedableRng};
-use rand_xoshiro::Xoshiro128StarStar;
-
-pub fn provide(providers: &mut ty::query::Providers) {
- *providers =
- ty::query::Providers { layout_of, fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers };
-}
-
pub trait IntegerExt {
fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>;
fn from_attr<C: HasDataLayout>(cx: &C, ity: attr::IntType) -> Integer;
@@ -207,6 +189,31 @@ pub enum LayoutError<'tcx> {
NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
}
+impl<'a> IntoDiagnostic<'a, !> for LayoutError<'a> {
+ fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, !> {
+ let mut diag = handler.struct_fatal("");
+
+ match self {
+ LayoutError::Unknown(ty) => {
+ diag.set_arg("ty", ty);
+ diag.set_primary_message(rustc_errors::fluent::middle_unknown_layout);
+ }
+ LayoutError::SizeOverflow(ty) => {
+ diag.set_arg("ty", ty);
+ diag.set_primary_message(rustc_errors::fluent::middle_values_too_big);
+ }
+ LayoutError::NormalizationFailure(ty, e) => {
+ diag.set_arg("ty", ty);
+ diag.set_arg("failure_ty", e.get_type_for_failure());
+ diag.set_primary_message(rustc_errors::fluent::middle_cannot_be_normalized);
+ }
+ }
+ diag
+ }
+}
+
+// FIXME: Once the other errors that embed this error have been converted to translateable
+// diagnostics, this Display impl should be removed.
impl<'tcx> fmt::Display for LayoutError<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
@@ -224,1814 +231,12 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
}
}
-#[instrument(skip(tcx, query), level = "debug")]
-fn layout_of<'tcx>(
- tcx: TyCtxt<'tcx>,
- query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
-) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
- let (param_env, ty) = query.into_parts();
- debug!(?ty);
-
- let param_env = param_env.with_reveal_all_normalized(tcx);
- let unnormalized_ty = ty;
-
- // FIXME: We might want to have two different versions of `layout_of`:
- // One that can be called after typecheck has completed and can use
- // `normalize_erasing_regions` here and another one that can be called
- // before typecheck has completed and uses `try_normalize_erasing_regions`.
- let ty = match tcx.try_normalize_erasing_regions(param_env, ty) {
- Ok(t) => t,
- Err(normalization_error) => {
- return Err(LayoutError::NormalizationFailure(ty, normalization_error));
- }
- };
-
- if ty != unnormalized_ty {
- // Ensure this layout is also cached for the normalized type.
- return tcx.layout_of(param_env.and(ty));
- }
-
- let cx = LayoutCx { tcx, param_env };
-
- let layout = cx.layout_of_uncached(ty)?;
- let layout = TyAndLayout { ty, layout };
-
- cx.record_layout_for_printing(layout);
-
- sanity_check_layout(&cx, &layout);
-
- Ok(layout)
-}
-
#[derive(Clone, Copy)]
pub struct LayoutCx<'tcx, C> {
pub tcx: C,
pub param_env: ty::ParamEnv<'tcx>,
}
-#[derive(Copy, Clone, Debug)]
-enum StructKind {
- /// A tuple, closure, or univariant which cannot be coerced to unsized.
- AlwaysSized,
- /// A univariant, the last field of which may be coerced to unsized.
- MaybeUnsized,
- /// A univariant, but with a prefix of an arbitrary size & alignment (e.g., enum tag).
- Prefixed(Size, Align),
-}
-
-// Invert a bijective mapping, i.e. `invert(map)[y] = x` if `map[x] = y`.
-// 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.
-fn invert_mapping(map: &[u32]) -> Vec<u32> {
- let mut inverse = vec![0; map.len()];
- for i in 0..map.len() {
- inverse[map[i] as usize] = i as u32;
- }
- inverse
-}
-
-impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
- fn scalar_pair(&self, a: Scalar, b: Scalar) -> LayoutS<'tcx> {
- let dl = self.data_layout();
- let b_align = b.align(dl);
- let align = a.align(dl).max(b_align).max(dl.aggregate_align);
- let b_offset = a.size(dl).align_to(b_align.abi);
- let size = (b_offset + b.size(dl)).align_to(align.abi);
-
- // HACK(nox): We iter on `b` and then `a` because `max_by_key`
- // returns the last maximum.
- let largest_niche = Niche::from_scalar(dl, b_offset, b)
- .into_iter()
- .chain(Niche::from_scalar(dl, Size::ZERO, a))
- .max_by_key(|niche| niche.available(dl));
-
- LayoutS {
- variants: Variants::Single { index: VariantIdx::new(0) },
- fields: FieldsShape::Arbitrary {
- offsets: vec![Size::ZERO, b_offset],
- memory_index: vec![0, 1],
- },
- abi: Abi::ScalarPair(a, b),
- largest_niche,
- align,
- size,
- }
- }
-
- fn univariant_uninterned(
- &self,
- ty: Ty<'tcx>,
- fields: &[TyAndLayout<'_>],
- repr: &ReprOptions,
- kind: StructKind,
- ) -> Result<LayoutS<'tcx>, LayoutError<'tcx>> {
- let dl = self.data_layout();
- let pack = repr.pack;
- if pack.is_some() && repr.align.is_some() {
- self.tcx.sess.delay_span_bug(DUMMY_SP, "struct cannot be packed and aligned");
- return Err(LayoutError::Unknown(ty));
- }
-
- let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
-
- let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).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[..end];
- let field_align = |f: &TyAndLayout<'_>| {
- if let Some(pack) = pack { f.align.abi.min(pack) } else { f.align.abi }
- };
-
- // 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() {
- // `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.
- let f = &fields[x as usize];
- (!f.is_zst(), cmp::Reverse(field_align(f)))
- });
- }
-
- StructKind::Prefixed(..) => {
- // Sort in ascending alignment so that the layout stays optimal
- // regardless of the prefix
- optimizing.sort_by_key(|&x| field_align(&fields[x as usize]));
- }
- }
-
- // 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 = vec![Size::ZERO; fields.len()];
- 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 as usize];
- if !sized {
- self.tcx.sess.delay_span_bug(
- DUMMY_SP,
- &format!(
- "univariant: field #{} of `{}` comes after unsized field",
- offsets.len(),
- ty
- ),
- );
- }
-
- if field.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 as usize] = 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).ok_or(LayoutError::SizeOverflow(ty))?;
- }
-
- 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 { invert_mapping(&inverse_memory_index) } else { inverse_memory_index };
-
- 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().enumerate().filter(|&(_, f)| !f.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, &[0, 1]);
- offsets
- }
- _ => bug!(),
- };
- if offsets[i] == pair_offsets[0]
- && offsets[j] == pair_offsets[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;
- }
-
- Ok(LayoutS {
- variants: Variants::Single { index: VariantIdx::new(0) },
- fields: FieldsShape::Arbitrary { offsets, memory_index },
- abi,
- largest_niche,
- align,
- size,
- })
- }
-
- fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
- let tcx = self.tcx;
- let param_env = self.param_env;
- let dl = self.data_layout();
- let scalar_unit = |value: Primitive| {
- let size = value.size(dl);
- assert!(size.bits() <= 128);
- Scalar::Initialized { value, valid_range: WrappingRange::full(size) }
- };
- let scalar =
- |value: Primitive| tcx.intern_layout(LayoutS::scalar(self, scalar_unit(value)));
-
- let univariant = |fields: &[TyAndLayout<'_>], repr: &ReprOptions, kind| {
- Ok(tcx.intern_layout(self.univariant_uninterned(ty, fields, repr, kind)?))
- };
- debug_assert!(!ty.has_infer_types_or_consts());
-
- Ok(match *ty.kind() {
- // Basic scalars.
- ty::Bool => tcx.intern_layout(LayoutS::scalar(
- self,
- Scalar::Initialized {
- value: Int(I8, false),
- valid_range: WrappingRange { start: 0, end: 1 },
- },
- )),
- ty::Char => tcx.intern_layout(LayoutS::scalar(
- self,
- Scalar::Initialized {
- value: Int(I32, false),
- valid_range: WrappingRange { start: 0, end: 0x10FFFF },
- },
- )),
- ty::Int(ity) => scalar(Int(Integer::from_int_ty(dl, ity), true)),
- ty::Uint(ity) => scalar(Int(Integer::from_uint_ty(dl, ity), false)),
- ty::Float(fty) => scalar(match fty {
- ty::FloatTy::F32 => F32,
- ty::FloatTy::F64 => F64,
- }),
- ty::FnPtr(_) => {
- let mut ptr = scalar_unit(Pointer);
- ptr.valid_range_mut().start = 1;
- tcx.intern_layout(LayoutS::scalar(self, ptr))
- }
-
- // The never type.
- ty::Never => tcx.intern_layout(LayoutS {
- variants: Variants::Single { index: VariantIdx::new(0) },
- fields: FieldsShape::Primitive,
- abi: Abi::Uninhabited,
- largest_niche: None,
- align: dl.i8_align,
- size: Size::ZERO,
- }),
-
- // Potentially-wide pointers.
- ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
- let mut data_ptr = scalar_unit(Pointer);
- if !ty.is_unsafe_ptr() {
- data_ptr.valid_range_mut().start = 1;
- }
-
- let pointee = tcx.normalize_erasing_regions(param_env, pointee);
- if pointee.is_sized(tcx.at(DUMMY_SP), param_env) {
- return Ok(tcx.intern_layout(LayoutS::scalar(self, data_ptr)));
- }
-
- let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
- let metadata = match unsized_part.kind() {
- ty::Foreign(..) => {
- return Ok(tcx.intern_layout(LayoutS::scalar(self, data_ptr)));
- }
- ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
- ty::Dynamic(..) => {
- let mut vtable = scalar_unit(Pointer);
- vtable.valid_range_mut().start = 1;
- vtable
- }
- _ => return Err(LayoutError::Unknown(unsized_part)),
- };
-
- // Effectively a (ptr, meta) tuple.
- tcx.intern_layout(self.scalar_pair(data_ptr, metadata))
- }
-
- ty::Dynamic(_, _, ty::DynStar) => {
- let mut data = scalar_unit(Int(dl.ptr_sized_integer(), false));
- data.valid_range_mut().start = 0;
- let mut vtable = scalar_unit(Pointer);
- vtable.valid_range_mut().start = 1;
- tcx.intern_layout(self.scalar_pair(data, vtable))
- }
-
- // Arrays and slices.
- ty::Array(element, mut count) => {
- if count.has_projections() {
- count = tcx.normalize_erasing_regions(param_env, count);
- if count.has_projections() {
- return Err(LayoutError::Unknown(ty));
- }
- }
-
- let count = count.try_eval_usize(tcx, param_env).ok_or(LayoutError::Unknown(ty))?;
- let element = self.layout_of(element)?;
- let size =
- element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow(ty))?;
-
- let abi =
- if count != 0 && tcx.conservative_is_privately_uninhabited(param_env.and(ty)) {
- Abi::Uninhabited
- } else {
- Abi::Aggregate { sized: true }
- };
-
- let largest_niche = if count != 0 { element.largest_niche } else { None };
-
- tcx.intern_layout(LayoutS {
- variants: Variants::Single { index: VariantIdx::new(0) },
- fields: FieldsShape::Array { stride: element.size, count },
- abi,
- largest_niche,
- align: element.align,
- size,
- })
- }
- ty::Slice(element) => {
- let element = self.layout_of(element)?;
- tcx.intern_layout(LayoutS {
- variants: Variants::Single { index: VariantIdx::new(0) },
- fields: FieldsShape::Array { stride: element.size, count: 0 },
- abi: Abi::Aggregate { sized: false },
- largest_niche: None,
- align: element.align,
- size: Size::ZERO,
- })
- }
- ty::Str => tcx.intern_layout(LayoutS {
- variants: Variants::Single { index: VariantIdx::new(0) },
- fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
- abi: Abi::Aggregate { sized: false },
- largest_niche: None,
- align: dl.i8_align,
- size: Size::ZERO,
- }),
-
- // Odd unit types.
- ty::FnDef(..) => univariant(&[], &ReprOptions::default(), StructKind::AlwaysSized)?,
- ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => {
- let mut unit = self.univariant_uninterned(
- ty,
- &[],
- &ReprOptions::default(),
- StructKind::AlwaysSized,
- )?;
- match unit.abi {
- Abi::Aggregate { ref mut sized } => *sized = false,
- _ => bug!(),
- }
- tcx.intern_layout(unit)
- }
-
- ty::Generator(def_id, substs, _) => self.generator_layout(ty, def_id, substs)?,
-
- ty::Closure(_, ref substs) => {
- let tys = substs.as_closure().upvar_tys();
- univariant(
- &tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
- &ReprOptions::default(),
- StructKind::AlwaysSized,
- )?
- }
-
- ty::Tuple(tys) => {
- let kind =
- if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
-
- univariant(
- &tys.iter().map(|k| self.layout_of(k)).collect::<Result<Vec<_>, _>>()?,
- &ReprOptions::default(),
- kind,
- )?
- }
-
- // SIMD vector types.
- ty::Adt(def, substs) if def.repr().simd() => {
- if !def.is_struct() {
- // Should have yielded E0517 by now.
- tcx.sess.delay_span_bug(
- DUMMY_SP,
- "#[repr(simd)] was applied to an ADT that is not a struct",
- );
- return Err(LayoutError::Unknown(ty));
- }
-
- // Supported SIMD vectors are homogeneous ADTs with at least one field:
- //
- // * #[repr(simd)] struct S(T, T, T, T);
- // * #[repr(simd)] struct S { x: T, y: T, z: T, w: T }
- // * #[repr(simd)] struct S([T; 4])
- //
- // where T is a primitive scalar (integer/float/pointer).
-
- // SIMD vectors with zero fields are not supported.
- // (should be caught by typeck)
- if def.non_enum_variant().fields.is_empty() {
- tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty));
- }
-
- // Type of the first ADT field:
- let f0_ty = def.non_enum_variant().fields[0].ty(tcx, substs);
-
- // Heterogeneous SIMD vectors are not supported:
- // (should be caught by typeck)
- for fi in &def.non_enum_variant().fields {
- if fi.ty(tcx, substs) != f0_ty {
- tcx.sess.fatal(&format!("monomorphising heterogeneous SIMD type `{}`", ty));
- }
- }
-
- // The element type and number of elements of the SIMD vector
- // are obtained from:
- //
- // * the element type and length of the single array field, if
- // the first field is of array type, or
- //
- // * the homogeneous field type and the number of fields.
- let (e_ty, e_len, is_array) = if let ty::Array(e_ty, _) = f0_ty.kind() {
- // First ADT field is an array:
-
- // SIMD vectors with multiple array fields are not supported:
- // (should be caught by typeck)
- if def.non_enum_variant().fields.len() != 1 {
- tcx.sess.fatal(&format!(
- "monomorphising SIMD type `{}` with more than one array field",
- ty
- ));
- }
-
- // Extract the number of elements from the layout of the array field:
- let FieldsShape::Array { count, .. } = self.layout_of(f0_ty)?.layout.fields() else {
- return Err(LayoutError::Unknown(ty));
- };
-
- (*e_ty, *count, true)
- } else {
- // First ADT field is not an array:
- (f0_ty, def.non_enum_variant().fields.len() as _, false)
- };
-
- // SIMD vectors of zero length are not supported.
- // Additionally, lengths are capped at 2^16 as a fixed maximum backends must
- // support.
- //
- // Can't be caught in typeck if the array length is generic.
- if e_len == 0 {
- tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty));
- } else if e_len > MAX_SIMD_LANES {
- tcx.sess.fatal(&format!(
- "monomorphising SIMD type `{}` of length greater than {}",
- ty, MAX_SIMD_LANES,
- ));
- }
-
- // Compute the ABI of the element type:
- let e_ly = self.layout_of(e_ty)?;
- let Abi::Scalar(e_abi) = e_ly.abi else {
- // This error isn't caught in typeck, e.g., if
- // the element type of the vector is generic.
- tcx.sess.fatal(&format!(
- "monomorphising SIMD type `{}` with a non-primitive-scalar \
- (integer/float/pointer) element type `{}`",
- ty, e_ty
- ))
- };
-
- // Compute the size and alignment of the vector:
- let size = e_ly.size.checked_mul(e_len, dl).ok_or(LayoutError::SizeOverflow(ty))?;
- let align = dl.vector_align(size);
- let size = size.align_to(align.abi);
-
- // Compute the placement of the vector fields:
- let fields = if is_array {
- FieldsShape::Arbitrary { offsets: vec![Size::ZERO], memory_index: vec![0] }
- } else {
- FieldsShape::Array { stride: e_ly.size, count: e_len }
- };
-
- tcx.intern_layout(LayoutS {
- variants: Variants::Single { index: VariantIdx::new(0) },
- fields,
- abi: Abi::Vector { element: e_abi, count: e_len },
- largest_niche: e_ly.largest_niche,
- size,
- align,
- })
- }
-
- // ADTs.
- ty::Adt(def, substs) => {
- // Cache the field layouts.
- let variants = def
- .variants()
- .iter()
- .map(|v| {
- v.fields
- .iter()
- .map(|field| self.layout_of(field.ty(tcx, substs)))
- .collect::<Result<Vec<_>, _>>()
- })
- .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
-
- if def.is_union() {
- if def.repr().pack.is_some() && def.repr().align.is_some() {
- self.tcx.sess.delay_span_bug(
- tcx.def_span(def.did()),
- "union cannot be packed and aligned",
- );
- return Err(LayoutError::Unknown(ty));
- }
-
- let mut align =
- if def.repr().pack.is_some() { dl.i8_align } else { dl.aggregate_align };
-
- if let Some(repr_align) = def.repr().align {
- align = align.max(AbiAndPrefAlign::new(repr_align));
- }
-
- let optimize = !def.repr().inhibit_union_abi_opt();
- let mut size = Size::ZERO;
- let mut abi = Abi::Aggregate { sized: true };
- let index = VariantIdx::new(0);
- for field in &variants[index] {
- assert!(!field.is_unsized());
- align = align.max(field.align);
-
- // If all non-ZST fields have the same ABI, forward this ABI
- if optimize && !field.is_zst() {
- // 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 }
- }
- 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 };
- }
- }
-
- size = cmp::max(size, field.size);
- }
-
- if let Some(pack) = def.repr().pack {
- align = align.min(AbiAndPrefAlign::new(pack));
- }
-
- return Ok(tcx.intern_layout(LayoutS {
- variants: Variants::Single { index },
- fields: FieldsShape::Union(
- NonZeroUsize::new(variants[index].len())
- .ok_or(LayoutError::Unknown(ty))?,
- ),
- abi,
- largest_niche: None,
- align,
- size: size.align_to(align.abi),
- }));
- }
-
- // A variant is absent if it's uninhabited and only has ZST fields.
- // Present uninhabited variants only require space for their fields,
- // but *not* an encoding of the discriminant (e.g., a tag value).
- // See issue #49298 for more details on the need to leave space
- // for non-ZST uninhabited data (mostly partial initialization).
- let absent = |fields: &[TyAndLayout<'_>]| {
- let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited());
- let is_zst = fields.iter().all(|f| f.is_zst());
- uninhabited && is_zst
- };
- let (present_first, present_second) = {
- let mut present_variants = variants
- .iter_enumerated()
- .filter_map(|(i, v)| if absent(v) { None } else { Some(i) });
- (present_variants.next(), present_variants.next())
- };
- let present_first = match present_first {
- Some(present_first) => present_first,
- // Uninhabited because it has no variants, or only absent ones.
- None if def.is_enum() => {
- return Ok(tcx.layout_of(param_env.and(tcx.types.never))?.layout);
- }
- // If it's a struct, still compute a layout so that we can still compute the
- // field offsets.
- None => VariantIdx::new(0),
- };
-
- let is_struct = !def.is_enum() ||
- // Only one variant is present.
- (present_second.is_none() &&
- // Representation optimizations are allowed.
- !def.repr().inhibit_enum_layout_opt());
- if is_struct {
- // Struct, or univariant enum equivalent to a struct.
- // (Typechecking will reject discriminant-sizing attrs.)
-
- let v = present_first;
- let kind = if def.is_enum() || variants[v].is_empty() {
- StructKind::AlwaysSized
- } else {
- let param_env = tcx.param_env(def.did());
- let last_field = def.variant(v).fields.last().unwrap();
- let always_sized =
- tcx.type_of(last_field.did).is_sized(tcx.at(DUMMY_SP), param_env);
- if !always_sized {
- StructKind::MaybeUnsized
- } else {
- StructKind::AlwaysSized
- }
- };
-
- let mut st = self.univariant_uninterned(ty, &variants[v], &def.repr(), kind)?;
- st.variants = Variants::Single { index: v };
-
- if def.is_unsafe_cell() {
- let hide_niches = |scalar: &mut _| match scalar {
- Scalar::Initialized { value, valid_range } => {
- *valid_range = WrappingRange::full(value.size(dl))
- }
- // Already doesn't have any niches
- Scalar::Union { .. } => {}
- };
- match &mut st.abi {
- Abi::Uninhabited => {}
- Abi::Scalar(scalar) => hide_niches(scalar),
- Abi::ScalarPair(a, b) => {
- hide_niches(a);
- hide_niches(b);
- }
- Abi::Vector { element, count: _ } => hide_niches(element),
- Abi::Aggregate { sized: _ } => {}
- }
- st.largest_niche = None;
- return Ok(tcx.intern_layout(st));
- }
-
- let (start, end) = self.tcx.layout_scalar_valid_range(def.did());
- match st.abi {
- Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => {
- // the asserts ensure that we are not using the
- // `#[rustc_layout_scalar_valid_range(n)]`
- // attribute to widen the range of anything as that would probably
- // result in UB somewhere
- // FIXME(eddyb) the asserts are probably not needed,
- // as larger validity ranges would result in missed
- // optimizations, *not* wrongly assuming the inner
- // value is valid. e.g. unions enlarge validity ranges,
- // because the values may be uninitialized.
- if let Bound::Included(start) = start {
- // FIXME(eddyb) this might be incorrect - it doesn't
- // account for wrap-around (end < start) ranges.
- let valid_range = scalar.valid_range_mut();
- assert!(valid_range.start <= start);
- valid_range.start = start;
- }
- if let Bound::Included(end) = end {
- // FIXME(eddyb) this might be incorrect - it doesn't
- // account for wrap-around (end < start) ranges.
- let valid_range = scalar.valid_range_mut();
- assert!(valid_range.end >= end);
- valid_range.end = end;
- }
-
- // Update `largest_niche` if we have introduced a larger niche.
- let niche = Niche::from_scalar(dl, Size::ZERO, *scalar);
- if let Some(niche) = niche {
- match st.largest_niche {
- Some(largest_niche) => {
- // Replace the existing niche even if they're equal,
- // because this one is at a lower offset.
- if largest_niche.available(dl) <= niche.available(dl) {
- st.largest_niche = Some(niche);
- }
- }
- None => st.largest_niche = Some(niche),
- }
- }
- }
- _ => assert!(
- start == Bound::Unbounded && end == Bound::Unbounded,
- "nonscalar layout for layout_scalar_valid_range type {:?}: {:#?}",
- def,
- st,
- ),
- }
-
- return Ok(tcx.intern_layout(st));
- }
-
- // At this point, we have handled all unions and
- // structs. (We have also handled univariant enums
- // that allow representation optimization.)
- assert!(def.is_enum());
-
- // Until we've decided whether to use the tagged or
- // niche filling LayoutS, we don't want to intern the
- // variant layouts, so we can't store them in the
- // overall LayoutS. Store the overall LayoutS
- // and the variant LayoutSs here until then.
- struct TmpLayout<'tcx> {
- layout: LayoutS<'tcx>,
- variants: IndexVec<VariantIdx, LayoutS<'tcx>>,
- }
-
- let calculate_niche_filling_layout =
- || -> Result<Option<TmpLayout<'tcx>>, LayoutError<'tcx>> {
- // The current code for niche-filling relies on variant indices
- // instead of actual discriminants, so enums with
- // explicit discriminants (RFC #2363) would misbehave.
- if def.repr().inhibit_enum_layout_opt()
- || def
- .variants()
- .iter_enumerated()
- .any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32()))
- {
- return Ok(None);
- }
-
- if variants.len() < 2 {
- return Ok(None);
- }
-
- let mut align = dl.aggregate_align;
- let mut variant_layouts = variants
- .iter_enumerated()
- .map(|(j, v)| {
- let mut st = self.univariant_uninterned(
- ty,
- v,
- &def.repr(),
- StructKind::AlwaysSized,
- )?;
- st.variants = Variants::Single { index: j };
-
- align = align.max(st.align);
-
- Ok(st)
- })
- .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
-
- let largest_variant_index = match variant_layouts
- .iter_enumerated()
- .max_by_key(|(_i, layout)| layout.size.bytes())
- .map(|(i, _layout)| i)
- {
- None => return Ok(None),
- Some(i) => i,
- };
-
- let all_indices = VariantIdx::new(0)..=VariantIdx::new(variants.len() - 1);
- let needs_disc = |index: VariantIdx| {
- index != largest_variant_index && !absent(&variants[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;
-
- // Find the field with the largest niche
- let (field_index, niche, (niche_start, niche_scalar)) = match variants
- [largest_variant_index]
- .iter()
- .enumerate()
- .filter_map(|(j, field)| Some((j, field.largest_niche?)))
- .max_by_key(|(_, niche)| niche.available(dl))
- .and_then(|(j, niche)| Some((j, niche, niche.reserve(self, count)?)))
- {
- None => return Ok(None),
- Some(x) => x,
- };
-
- let niche_offset = niche.offset
- + variant_layouts[largest_variant_index].fields.offset(field_index);
- let niche_size = niche.value.size(dl);
- let size = variant_layouts[largest_variant_index].size.align_to(align.abi);
-
- let all_variants_fit =
- variant_layouts.iter_enumerated_mut().all(|(i, layout)| {
- if i == largest_variant_index {
- return true;
- }
-
- layout.largest_niche = None;
-
- if layout.size <= niche_offset {
- // This variant will fit before the niche.
- return true;
- }
-
- // Determine if it'll fit after the niche.
- let this_align = layout.align.abi;
- let this_offset = (niche_offset + niche_size).align_to(this_align);
-
- if this_offset + layout.size > size {
- return false;
- }
-
- // It'll fit, but we need to make some adjustments.
- match layout.fields {
- FieldsShape::Arbitrary { ref mut offsets, .. } => {
- for (j, offset) in offsets.iter_mut().enumerate() {
- if !variants[i][j].is_zst() {
- *offset += this_offset;
- }
- }
- }
- _ => {
- panic!("Layout of fields should be Arbitrary for variants")
- }
- }
-
- // It can't be a Scalar or ScalarPair because the offset isn't 0.
- if !layout.abi.is_uninhabited() {
- layout.abi = Abi::Aggregate { sized: true };
- }
- layout.size += this_offset;
-
- true
- });
-
- if !all_variants_fit {
- return Ok(None);
- }
-
- let largest_niche = Niche::from_scalar(dl, niche_offset, niche_scalar);
-
- let others_zst = variant_layouts.iter_enumerated().all(|(i, layout)| {
- i == largest_variant_index || layout.size == Size::ZERO
- });
- let same_size = size == variant_layouts[largest_variant_index].size;
- let same_align = align == variant_layouts[largest_variant_index].align;
-
- let abi = if variant_layouts.iter().all(|v| v.abi.is_uninhabited()) {
- Abi::Uninhabited
- } else if same_size && same_align && others_zst {
- match variant_layouts[largest_variant_index].abi {
- // When the total alignment and size match, we can use the
- // same ABI as the scalar variant with the reserved niche.
- Abi::Scalar(_) => Abi::Scalar(niche_scalar),
- Abi::ScalarPair(first, second) => {
- // Only the niche is guaranteed to be initialised,
- // so use union layouts for the other primitive.
- if niche_offset == Size::ZERO {
- Abi::ScalarPair(niche_scalar, second.to_union())
- } else {
- Abi::ScalarPair(first.to_union(), niche_scalar)
- }
- }
- _ => Abi::Aggregate { sized: true },
- }
- } else {
- Abi::Aggregate { sized: true }
- };
-
- let layout = LayoutS {
- variants: Variants::Multiple {
- tag: niche_scalar,
- tag_encoding: TagEncoding::Niche {
- untagged_variant: largest_variant_index,
- niche_variants,
- niche_start,
- },
- tag_field: 0,
- variants: IndexVec::new(),
- },
- fields: FieldsShape::Arbitrary {
- offsets: vec![niche_offset],
- memory_index: vec![0],
- },
- abi,
- largest_niche,
- size,
- align,
- };
-
- Ok(Some(TmpLayout { layout, variants: variant_layouts }))
- };
-
- let niche_filling_layout = calculate_niche_filling_layout()?;
-
- let (mut min, mut max) = (i128::MAX, i128::MIN);
- let discr_type = def.repr().discr_type();
- let bits = Integer::from_attr(self, discr_type).size().bits();
- for (i, discr) in def.discriminants(tcx) {
- if variants[i].iter().any(|f| f.abi.is_uninhabited()) {
- continue;
- }
- let mut x = discr.val as i128;
- if discr_type.is_signed() {
- // sign extend the raw representation to be an i128
- x = (x << (128 - bits)) >> (128 - bits);
- }
- if x < min {
- min = x;
- }
- if x > max {
- max = x;
- }
- }
- // We might have no inhabited variants, so pretend there's at least one.
- if (min, max) == (i128::MAX, i128::MIN) {
- min = 0;
- max = 0;
- }
- assert!(min <= max, "discriminant range is {}...{}", min, max);
- let (min_ity, signed) = Integer::repr_discr(tcx, ty, &def.repr(), min, max);
-
- let mut align = dl.aggregate_align;
- let mut size = Size::ZERO;
-
- // We're interested in the smallest alignment, so start large.
- let mut start_align = Align::from_bytes(256).unwrap();
- assert_eq!(Integer::for_align(dl, start_align), None);
-
- // repr(C) on an enum tells us to make a (tag, union) layout,
- // so we need to grow the prefix alignment to be at least
- // the alignment of the union. (This value is used both for
- // determining the alignment of the overall enum, and the
- // determining the alignment of the payload after the tag.)
- let mut prefix_align = min_ity.align(dl).abi;
- if def.repr().c() {
- for fields in &variants {
- for field in fields {
- prefix_align = prefix_align.max(field.align.abi);
- }
- }
- }
-
- // Create the set of structs that represent each variant.
- let mut layout_variants = variants
- .iter_enumerated()
- .map(|(i, field_layouts)| {
- let mut st = self.univariant_uninterned(
- ty,
- &field_layouts,
- &def.repr(),
- StructKind::Prefixed(min_ity.size(), prefix_align),
- )?;
- st.variants = Variants::Single { index: i };
- // Find the first field we can't move later
- // to make room for a larger discriminant.
- for field in
- st.fields.index_by_increasing_offset().map(|j| field_layouts[j])
- {
- if !field.is_zst() || field.align.abi.bytes() != 1 {
- start_align = start_align.min(field.align.abi);
- break;
- }
- }
- size = cmp::max(size, st.size);
- align = align.max(st.align);
- Ok(st)
- })
- .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
-
- // Align the maximum variant size to the largest alignment.
- size = size.align_to(align.abi);
-
- if size.bytes() >= dl.obj_size_bound() {
- return Err(LayoutError::SizeOverflow(ty));
- }
-
- let typeck_ity = Integer::from_attr(dl, def.repr().discr_type());
- if typeck_ity < min_ity {
- // It is a bug if Layout decided on a greater discriminant size than typeck for
- // some reason at this point (based on values discriminant can take on). Mostly
- // because this discriminant will be loaded, and then stored into variable of
- // type calculated by typeck. Consider such case (a bug): typeck decided on
- // byte-sized discriminant, but layout thinks we need a 16-bit to store all
- // discriminant values. That would be a bug, because then, in codegen, in order
- // to store this 16-bit discriminant into 8-bit sized temporary some of the
- // space necessary to represent would have to be discarded (or layout is wrong
- // on thinking it needs 16 bits)
- bug!(
- "layout decided on a larger discriminant type ({:?}) than typeck ({:?})",
- min_ity,
- typeck_ity
- );
- // However, it is fine to make discr type however large (as an optimisation)
- // after this point – we’ll just truncate the value we load in codegen.
- }
-
- // Check to see if we should use a different type for the
- // discriminant. We can safely use a type with the same size
- // as the alignment of the first field of each variant.
- // We increase the size of the discriminant to avoid LLVM copying
- // padding when it doesn't need to. This normally causes unaligned
- // load/stores and excessive memcpy/memset operations. By using a
- // bigger integer size, LLVM can be sure about its contents and
- // won't be so conservative.
-
- // Use the initial field alignment
- let mut ity = if def.repr().c() || def.repr().int.is_some() {
- min_ity
- } else {
- Integer::for_align(dl, start_align).unwrap_or(min_ity)
- };
-
- // If the alignment is not larger than the chosen discriminant size,
- // don't use the alignment as the final size.
- if ity <= min_ity {
- ity = min_ity;
- } else {
- // Patch up the variants' first few fields.
- let old_ity_size = min_ity.size();
- let new_ity_size = ity.size();
- for variant in &mut layout_variants {
- match variant.fields {
- FieldsShape::Arbitrary { ref mut offsets, .. } => {
- for i in offsets {
- if *i <= old_ity_size {
- assert_eq!(*i, old_ity_size);
- *i = new_ity_size;
- }
- }
- // We might be making the struct larger.
- if variant.size <= old_ity_size {
- variant.size = new_ity_size;
- }
- }
- _ => bug!(),
- }
- }
- }
-
- let tag_mask = ity.size().unsigned_int_max();
- let tag = Scalar::Initialized {
- value: Int(ity, signed),
- valid_range: WrappingRange {
- start: (min as u128 & tag_mask),
- end: (max as u128 & tag_mask),
- },
- };
- let mut abi = Abi::Aggregate { sized: true };
-
- if layout_variants.iter().all(|v| v.abi.is_uninhabited()) {
- abi = Abi::Uninhabited;
- } else if tag.size(dl) == size {
- // Make sure we only use scalar layout when the enum is entirely its
- // own tag (i.e. it has no padding nor any non-ZST variant fields).
- abi = Abi::Scalar(tag);
- } else {
- // Try to use a ScalarPair for all tagged enums.
- let mut common_prim = None;
- let mut common_prim_initialized_in_all_variants = true;
- for (field_layouts, layout_variant) in iter::zip(&variants, &layout_variants) {
- let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else {
- bug!();
- };
- let mut fields =
- iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst());
- let (field, offset) = match (fields.next(), fields.next()) {
- (None, None) => {
- common_prim_initialized_in_all_variants = false;
- continue;
- }
- (Some(pair), None) => pair,
- _ => {
- common_prim = None;
- break;
- }
- };
- let prim = match field.abi {
- Abi::Scalar(scalar) => {
- common_prim_initialized_in_all_variants &=
- matches!(scalar, Scalar::Initialized { .. });
- scalar.primitive()
- }
- _ => {
- common_prim = None;
- break;
- }
- };
- if let Some(pair) = common_prim {
- // This is pretty conservative. We could go fancier
- // by conflating things like i32 and u32, or even
- // realising that (u8, u8) could just cohabit with
- // u16 or even u32.
- if pair != (prim, offset) {
- common_prim = None;
- break;
- }
- } else {
- common_prim = Some((prim, offset));
- }
- }
- if let Some((prim, offset)) = common_prim {
- let prim_scalar = if common_prim_initialized_in_all_variants {
- scalar_unit(prim)
- } else {
- // Common prim might be uninit.
- Scalar::Union { value: prim }
- };
- let pair = self.scalar_pair(tag, prim_scalar);
- let pair_offsets = match pair.fields {
- FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
- assert_eq!(memory_index, &[0, 1]);
- offsets
- }
- _ => bug!(),
- };
- if pair_offsets[0] == Size::ZERO
- && pair_offsets[1] == *offset
- && 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 we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the
- // variants to ensure they are consistent. This is because a downcast is
- // semantically a NOP, and thus should not affect layout.
- if matches!(abi, Abi::Scalar(..) | Abi::ScalarPair(..)) {
- for variant in &mut layout_variants {
- // We only do this for variants with fields; the others are not accessed anyway.
- // Also do not overwrite any already existing "clever" ABIs.
- if variant.fields.count() > 0
- && matches!(variant.abi, Abi::Aggregate { .. })
- {
- variant.abi = abi;
- // Also need to bump up the size and alignment, so that the entire value fits in here.
- variant.size = cmp::max(variant.size, size);
- variant.align.abi = cmp::max(variant.align.abi, align.abi);
- }
- }
- }
-
- let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
-
- let tagged_layout = LayoutS {
- variants: Variants::Multiple {
- tag,
- tag_encoding: TagEncoding::Direct,
- tag_field: 0,
- variants: IndexVec::new(),
- },
- fields: FieldsShape::Arbitrary {
- offsets: vec![Size::ZERO],
- memory_index: vec![0],
- },
- largest_niche,
- abi,
- align,
- size,
- };
-
- let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants };
-
- let mut best_layout = match (tagged_layout, niche_filling_layout) {
- (tl, Some(nl)) => {
- // Pick the smaller layout; otherwise,
- // pick the layout with the larger niche; otherwise,
- // pick tagged as it has simpler codegen.
- use Ordering::*;
- let niche_size = |tmp_l: &TmpLayout<'_>| {
- tmp_l.layout.largest_niche.map_or(0, |n| n.available(dl))
- };
- match (
- tl.layout.size.cmp(&nl.layout.size),
- niche_size(&tl).cmp(&niche_size(&nl)),
- ) {
- (Greater, _) => nl,
- (Equal, Less) => nl,
- _ => tl,
- }
- }
- (tl, None) => tl,
- };
-
- // Now we can intern the variant layouts and store them in the enum layout.
- best_layout.layout.variants = match best_layout.layout.variants {
- Variants::Multiple { tag, tag_encoding, tag_field, .. } => Variants::Multiple {
- tag,
- tag_encoding,
- tag_field,
- variants: best_layout
- .variants
- .into_iter()
- .map(|layout| tcx.intern_layout(layout))
- .collect(),
- },
- _ => bug!(),
- };
-
- tcx.intern_layout(best_layout.layout)
- }
-
- // Types with no meaningful known layout.
- ty::Projection(_) | ty::Opaque(..) => {
- // NOTE(eddyb) `layout_of` query should've normalized these away,
- // if that was possible, so there's no reason to try again here.
- return Err(LayoutError::Unknown(ty));
- }
-
- ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => {
- bug!("Layout::compute: unexpected type `{}`", ty)
- }
-
- ty::Bound(..) | ty::Param(_) | ty::Error(_) => {
- return Err(LayoutError::Unknown(ty));
- }
- })
- }
-}
-
-/// Overlap eligibility and variant assignment for each GeneratorSavedLocal.
-#[derive(Clone, Debug, PartialEq)]
-enum SavedLocalEligibility {
- Unassigned,
- Assigned(VariantIdx),
- // FIXME: Use newtype_index so we aren't wasting bytes
- Ineligible(Option<u32>),
-}
-
-// When laying out generators, we divide our saved local fields into two
-// categories: overlap-eligible and overlap-ineligible.
-//
-// Those fields which are ineligible for overlap go in a "prefix" at the
-// beginning of the layout, and always have space reserved for them.
-//
-// Overlap-eligible fields are only assigned to one variant, so we lay
-// those fields out for each variant and put them right after the
-// prefix.
-//
-// Finally, in the layout details, we point to the fields from the
-// variants they are assigned to. It is possible for some fields to be
-// included in multiple variants. No field ever "moves around" in the
-// layout; its offset is always the same.
-//
-// Also included in the layout are the upvars and the discriminant.
-// These are included as fields on the "outer" layout; they are not part
-// of any variant.
-impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
- /// Compute the eligibility and assignment of each local.
- fn generator_saved_local_eligibility(
- &self,
- info: &GeneratorLayout<'tcx>,
- ) -> (BitSet<GeneratorSavedLocal>, IndexVec<GeneratorSavedLocal, SavedLocalEligibility>) {
- use SavedLocalEligibility::*;
-
- let mut assignments: IndexVec<GeneratorSavedLocal, SavedLocalEligibility> =
- IndexVec::from_elem_n(Unassigned, info.field_tys.len());
-
- // The saved locals not eligible for overlap. These will get
- // "promoted" to the prefix of our generator.
- let mut ineligible_locals = BitSet::new_empty(info.field_tys.len());
-
- // Figure out which of our saved locals are fields in only
- // one variant. The rest are deemed ineligible for overlap.
- for (variant_index, fields) in info.variant_fields.iter_enumerated() {
- for local in fields {
- match assignments[*local] {
- Unassigned => {
- assignments[*local] = Assigned(variant_index);
- }
- Assigned(idx) => {
- // We've already seen this local at another suspension
- // point, so it is no longer a candidate.
- trace!(
- "removing local {:?} in >1 variant ({:?}, {:?})",
- local,
- variant_index,
- idx
- );
- ineligible_locals.insert(*local);
- assignments[*local] = Ineligible(None);
- }
- Ineligible(_) => {}
- }
- }
- }
-
- // Next, check every pair of eligible locals to see if they
- // conflict.
- for local_a in info.storage_conflicts.rows() {
- let conflicts_a = info.storage_conflicts.count(local_a);
- if ineligible_locals.contains(local_a) {
- continue;
- }
-
- for local_b in info.storage_conflicts.iter(local_a) {
- // local_a and local_b are storage live at the same time, therefore they
- // cannot overlap in the generator layout. The only way to guarantee
- // this is if they are in the same variant, or one is ineligible
- // (which means it is stored in every variant).
- if ineligible_locals.contains(local_b)
- || assignments[local_a] == assignments[local_b]
- {
- continue;
- }
-
- // If they conflict, we will choose one to make ineligible.
- // This is not always optimal; it's just a greedy heuristic that
- // seems to produce good results most of the time.
- let conflicts_b = info.storage_conflicts.count(local_b);
- let (remove, other) =
- if conflicts_a > conflicts_b { (local_a, local_b) } else { (local_b, local_a) };
- ineligible_locals.insert(remove);
- assignments[remove] = Ineligible(None);
- trace!("removing local {:?} due to conflict with {:?}", remove, other);
- }
- }
-
- // Count the number of variants in use. If only one of them, then it is
- // impossible to overlap any locals in our layout. In this case it's
- // always better to make the remaining locals ineligible, so we can
- // lay them out with the other locals in the prefix and eliminate
- // unnecessary padding bytes.
- {
- let mut used_variants = BitSet::new_empty(info.variant_fields.len());
- for assignment in &assignments {
- if let Assigned(idx) = assignment {
- used_variants.insert(*idx);
- }
- }
- if used_variants.count() < 2 {
- for assignment in assignments.iter_mut() {
- *assignment = Ineligible(None);
- }
- ineligible_locals.insert_all();
- }
- }
-
- // Write down the order of our locals that will be promoted to the prefix.
- {
- for (idx, local) in ineligible_locals.iter().enumerate() {
- assignments[local] = Ineligible(Some(idx as u32));
- }
- }
- debug!("generator saved local assignments: {:?}", assignments);
-
- (ineligible_locals, assignments)
- }
-
- /// Compute the full generator layout.
- fn generator_layout(
- &self,
- ty: Ty<'tcx>,
- def_id: hir::def_id::DefId,
- substs: SubstsRef<'tcx>,
- ) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
- use SavedLocalEligibility::*;
- let tcx = self.tcx;
- let subst_field = |ty: Ty<'tcx>| EarlyBinder(ty).subst(tcx, substs);
-
- let Some(info) = tcx.generator_layout(def_id) else {
- return Err(LayoutError::Unknown(ty));
- };
- let (ineligible_locals, assignments) = self.generator_saved_local_eligibility(&info);
-
- // Build a prefix layout, including "promoting" all ineligible
- // locals as part of the prefix. We compute the layout of all of
- // these fields at once to get optimal packing.
- let tag_index = substs.as_generator().prefix_tys().count();
-
- // `info.variant_fields` already accounts for the reserved variants, so no need to add them.
- let max_discr = (info.variant_fields.len() - 1) as u128;
- let discr_int = Integer::fit_unsigned(max_discr);
- let discr_int_ty = discr_int.to_ty(tcx, false);
- let tag = Scalar::Initialized {
- value: Primitive::Int(discr_int, false),
- valid_range: WrappingRange { start: 0, end: max_discr },
- };
- let tag_layout = self.tcx.intern_layout(LayoutS::scalar(self, tag));
- let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout };
-
- let promoted_layouts = ineligible_locals
- .iter()
- .map(|local| subst_field(info.field_tys[local]))
- .map(|ty| tcx.mk_maybe_uninit(ty))
- .map(|ty| self.layout_of(ty));
- let prefix_layouts = substs
- .as_generator()
- .prefix_tys()
- .map(|ty| self.layout_of(ty))
- .chain(iter::once(Ok(tag_layout)))
- .chain(promoted_layouts)
- .collect::<Result<Vec<_>, _>>()?;
- let prefix = self.univariant_uninterned(
- ty,
- &prefix_layouts,
- &ReprOptions::default(),
- StructKind::AlwaysSized,
- )?;
-
- let (prefix_size, prefix_align) = (prefix.size, prefix.align);
-
- // Split the prefix layout into the "outer" fields (upvars and
- // discriminant) and the "promoted" fields. Promoted fields will
- // get included in each variant that requested them in
- // GeneratorLayout.
- debug!("prefix = {:#?}", prefix);
- let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields {
- FieldsShape::Arbitrary { mut offsets, memory_index } => {
- let mut inverse_memory_index = invert_mapping(&memory_index);
-
- // "a" (`0..b_start`) and "b" (`b_start..`) correspond to
- // "outer" and "promoted" fields respectively.
- let b_start = (tag_index + 1) as u32;
- let offsets_b = offsets.split_off(b_start as usize);
- let offsets_a = offsets;
-
- // Disentangle the "a" and "b" components of `inverse_memory_index`
- // by preserving the order but keeping only one disjoint "half" each.
- // FIXME(eddyb) build a better abstraction for permutations, if possible.
- let inverse_memory_index_b: Vec<_> =
- inverse_memory_index.iter().filter_map(|&i| i.checked_sub(b_start)).collect();
- inverse_memory_index.retain(|&i| i < b_start);
- let inverse_memory_index_a = inverse_memory_index;
-
- // Since `inverse_memory_index_{a,b}` each only refer to their
- // respective fields, they can be safely inverted
- let memory_index_a = invert_mapping(&inverse_memory_index_a);
- let memory_index_b = invert_mapping(&inverse_memory_index_b);
-
- let outer_fields =
- FieldsShape::Arbitrary { offsets: offsets_a, memory_index: memory_index_a };
- (outer_fields, offsets_b, memory_index_b)
- }
- _ => bug!(),
- };
-
- let mut size = prefix.size;
- let mut align = prefix.align;
- let variants = info
- .variant_fields
- .iter_enumerated()
- .map(|(index, variant_fields)| {
- // Only include overlap-eligible fields when we compute our variant layout.
- let variant_only_tys = variant_fields
- .iter()
- .filter(|local| match assignments[**local] {
- Unassigned => bug!(),
- Assigned(v) if v == index => true,
- Assigned(_) => bug!("assignment does not match variant"),
- Ineligible(_) => false,
- })
- .map(|local| subst_field(info.field_tys[*local]));
-
- let mut variant = self.univariant_uninterned(
- ty,
- &variant_only_tys
- .map(|ty| self.layout_of(ty))
- .collect::<Result<Vec<_>, _>>()?,
- &ReprOptions::default(),
- StructKind::Prefixed(prefix_size, prefix_align.abi),
- )?;
- variant.variants = Variants::Single { index };
-
- let FieldsShape::Arbitrary { offsets, memory_index } = variant.fields else {
- bug!();
- };
-
- // Now, stitch the promoted and variant-only fields back together in
- // the order they are mentioned by our GeneratorLayout.
- // Because we only use some subset (that can differ between variants)
- // of the promoted fields, we can't just pick those elements of the
- // `promoted_memory_index` (as we'd end up with gaps).
- // So instead, we build an "inverse memory_index", as if all of the
- // promoted fields were being used, but leave the elements not in the
- // subset as `INVALID_FIELD_IDX`, which we can filter out later to
- // obtain a valid (bijective) mapping.
- const INVALID_FIELD_IDX: u32 = !0;
- let mut combined_inverse_memory_index =
- vec![INVALID_FIELD_IDX; promoted_memory_index.len() + memory_index.len()];
- let mut offsets_and_memory_index = iter::zip(offsets, memory_index);
- let combined_offsets = variant_fields
- .iter()
- .enumerate()
- .map(|(i, local)| {
- let (offset, memory_index) = match assignments[*local] {
- Unassigned => bug!(),
- Assigned(_) => {
- let (offset, memory_index) =
- offsets_and_memory_index.next().unwrap();
- (offset, promoted_memory_index.len() as u32 + memory_index)
- }
- Ineligible(field_idx) => {
- let field_idx = field_idx.unwrap() as usize;
- (promoted_offsets[field_idx], promoted_memory_index[field_idx])
- }
- };
- combined_inverse_memory_index[memory_index as usize] = i as u32;
- offset
- })
- .collect();
-
- // Remove the unused slots and invert the mapping to obtain the
- // combined `memory_index` (also see previous comment).
- combined_inverse_memory_index.retain(|&i| i != INVALID_FIELD_IDX);
- let combined_memory_index = invert_mapping(&combined_inverse_memory_index);
-
- variant.fields = FieldsShape::Arbitrary {
- offsets: combined_offsets,
- memory_index: combined_memory_index,
- };
-
- size = size.max(variant.size);
- align = align.max(variant.align);
- Ok(tcx.intern_layout(variant))
- })
- .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
-
- size = size.align_to(align.abi);
-
- let abi =
- if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi().is_uninhabited()) {
- Abi::Uninhabited
- } else {
- Abi::Aggregate { sized: true }
- };
-
- let layout = tcx.intern_layout(LayoutS {
- variants: Variants::Multiple {
- tag,
- tag_encoding: TagEncoding::Direct,
- tag_field: tag_index,
- variants,
- },
- fields: outer_fields,
- abi,
- largest_niche: prefix.largest_niche,
- size,
- align,
- });
- debug!("generator layout ({:?}): {:#?}", ty, layout);
- Ok(layout)
- }
-
- /// This is invoked by the `layout_of` query to record the final
- /// layout of each type.
- #[inline(always)]
- fn record_layout_for_printing(&self, layout: TyAndLayout<'tcx>) {
- // If we are running with `-Zprint-type-sizes`, maybe record layouts
- // for dumping later.
- if self.tcx.sess.opts.unstable_opts.print_type_sizes {
- self.record_layout_for_printing_outlined(layout)
- }
- }
-
- fn record_layout_for_printing_outlined(&self, layout: TyAndLayout<'tcx>) {
- // Ignore layouts that are done with non-empty environments or
- // non-monomorphic layouts, as the user only wants to see the stuff
- // resulting from the final codegen session.
- if layout.ty.has_param_types_or_consts() || !self.param_env.caller_bounds().is_empty() {
- return;
- }
-
- // (delay format until we actually need it)
- let record = |kind, packed, opt_discr_size, variants| {
- let type_desc = format!("{:?}", layout.ty);
- self.tcx.sess.code_stats.record_type_size(
- kind,
- type_desc,
- layout.align.abi,
- layout.size,
- packed,
- opt_discr_size,
- variants,
- );
- };
-
- let adt_def = match *layout.ty.kind() {
- ty::Adt(ref adt_def, _) => {
- debug!("print-type-size t: `{:?}` process adt", layout.ty);
- adt_def
- }
-
- ty::Closure(..) => {
- debug!("print-type-size t: `{:?}` record closure", layout.ty);
- record(DataTypeKind::Closure, false, None, vec![]);
- return;
- }
-
- _ => {
- debug!("print-type-size t: `{:?}` skip non-nominal", layout.ty);
- return;
- }
- };
-
- let adt_kind = adt_def.adt_kind();
- let adt_packed = adt_def.repr().pack.is_some();
-
- let build_variant_info = |n: Option<Symbol>, flds: &[Symbol], layout: TyAndLayout<'tcx>| {
- let mut min_size = Size::ZERO;
- let field_info: Vec<_> = flds
- .iter()
- .enumerate()
- .map(|(i, &name)| {
- let field_layout = layout.field(self, i);
- let offset = layout.fields.offset(i);
- let field_end = offset + field_layout.size;
- if min_size < field_end {
- min_size = field_end;
- }
- FieldInfo {
- name,
- offset: offset.bytes(),
- size: field_layout.size.bytes(),
- align: field_layout.align.abi.bytes(),
- }
- })
- .collect();
-
- VariantInfo {
- name: n,
- kind: if layout.is_unsized() { SizeKind::Min } else { SizeKind::Exact },
- align: layout.align.abi.bytes(),
- size: if min_size.bytes() == 0 { layout.size.bytes() } else { min_size.bytes() },
- fields: field_info,
- }
- };
-
- match layout.variants {
- Variants::Single { index } => {
- if !adt_def.variants().is_empty() && layout.fields != FieldsShape::Primitive {
- debug!(
- "print-type-size `{:#?}` variant {}",
- layout,
- adt_def.variant(index).name
- );
- let variant_def = &adt_def.variant(index);
- let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
- record(
- adt_kind.into(),
- adt_packed,
- None,
- vec![build_variant_info(Some(variant_def.name), &fields, layout)],
- );
- } else {
- // (This case arises for *empty* enums; so give it
- // zero variants.)
- record(adt_kind.into(), adt_packed, None, vec![]);
- }
- }
-
- Variants::Multiple { tag, ref tag_encoding, .. } => {
- debug!(
- "print-type-size `{:#?}` adt general variants def {}",
- layout.ty,
- adt_def.variants().len()
- );
- let variant_infos: Vec<_> = adt_def
- .variants()
- .iter_enumerated()
- .map(|(i, variant_def)| {
- let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
- build_variant_info(
- Some(variant_def.name),
- &fields,
- layout.for_variant(self, i),
- )
- })
- .collect();
- record(
- adt_kind.into(),
- adt_packed,
- match tag_encoding {
- TagEncoding::Direct => Some(tag.size(self)),
- _ => None,
- },
- variant_infos,
- );
- }
- }
- }
-}
-
/// Type size "skeleton", i.e., the only information determining a type's size.
/// While this is conservative, (aside from constant sizes, only pointers,
/// newtypes thereof and null pointer optimized enums are allowed), it is
@@ -2058,7 +263,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> {
- debug_assert!(!ty.has_infer_types_or_consts());
+ debug_assert!(!ty.has_non_region_infer());
// First try computing a static layout.
let err = match tcx.layout_of(param_env.and(ty)) {
@@ -2074,7 +279,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
match tail.kind() {
ty::Param(_) | ty::Projection(_) => {
- debug_assert!(tail.has_param_types_or_consts());
+ debug_assert!(tail.has_non_region_param());
Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
}
_ => bug!(
@@ -2625,7 +830,7 @@ where
} else {
match mt {
hir::Mutability::Not => {
- if ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env()) {
+ if ty.is_freeze(tcx, cx.param_env()) {
PointerKind::Frozen
} else {
PointerKind::SharedMutable
@@ -2636,7 +841,7 @@ where
// noalias, as another pointer to the structure can be obtained, that
// is not based-on the original reference. We consider all !Unpin
// types to be potentially self-referential here.
- if ty.is_unpin(tcx.at(DUMMY_SP), cx.param_env()) {
+ if ty.is_unpin(tcx, cx.param_env()) {
PointerKind::UniqueBorrowed
} else {
PointerKind::UniqueBorrowedPinned
@@ -2748,112 +953,6 @@ where
}
}
-impl<'tcx> ty::Instance<'tcx> {
- // NOTE(eddyb) this is private to avoid using it from outside of
- // `fn_abi_of_instance` - any other uses are either too high-level
- // for `Instance` (e.g. typeck would use `Ty::fn_sig` instead),
- // or should go through `FnAbi` instead, to avoid losing any
- // adjustments `fn_abi_of_instance` might be performing.
- #[tracing::instrument(level = "debug", skip(tcx, param_env))]
- fn fn_sig_for_fn_abi(
- &self,
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ) -> ty::PolyFnSig<'tcx> {
- let ty = self.ty(tcx, param_env);
- match *ty.kind() {
- ty::FnDef(..) => {
- // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering
- // parameters unused if they show up in the signature, but not in the `mir::Body`
- // (i.e. due to being inside a projection that got normalized, see
- // `src/test/ui/polymorphization/normalized_sig_types.rs`), and codegen not keeping
- // track of a polymorphization `ParamEnv` to allow normalizing later.
- let mut sig = match *ty.kind() {
- ty::FnDef(def_id, substs) => tcx
- .normalize_erasing_regions(tcx.param_env(def_id), tcx.bound_fn_sig(def_id))
- .subst(tcx, substs),
- _ => unreachable!(),
- };
-
- if let ty::InstanceDef::VTableShim(..) = self.def {
- // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`.
- sig = sig.map_bound(|mut sig| {
- let mut inputs_and_output = sig.inputs_and_output.to_vec();
- inputs_and_output[0] = tcx.mk_mut_ptr(inputs_and_output[0]);
- sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output);
- sig
- });
- }
- sig
- }
- ty::Closure(def_id, substs) => {
- let sig = substs.as_closure().sig();
-
- let bound_vars = tcx.mk_bound_variable_kinds(
- sig.bound_vars()
- .iter()
- .chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))),
- );
- let br = ty::BoundRegion {
- var: ty::BoundVar::from_usize(bound_vars.len() - 1),
- kind: ty::BoundRegionKind::BrEnv,
- };
- let env_region = ty::ReLateBound(ty::INNERMOST, br);
- let env_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap();
-
- let sig = sig.skip_binder();
- ty::Binder::bind_with_vars(
- tcx.mk_fn_sig(
- iter::once(env_ty).chain(sig.inputs().iter().cloned()),
- sig.output(),
- sig.c_variadic,
- sig.unsafety,
- sig.abi,
- ),
- bound_vars,
- )
- }
- ty::Generator(_, substs, _) => {
- let sig = substs.as_generator().poly_sig();
-
- let bound_vars = tcx.mk_bound_variable_kinds(
- sig.bound_vars()
- .iter()
- .chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))),
- );
- let br = ty::BoundRegion {
- var: ty::BoundVar::from_usize(bound_vars.len() - 1),
- kind: ty::BoundRegionKind::BrEnv,
- };
- let env_region = ty::ReLateBound(ty::INNERMOST, br);
- let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
-
- let pin_did = tcx.require_lang_item(LangItem::Pin, None);
- let pin_adt_ref = tcx.adt_def(pin_did);
- let pin_substs = tcx.intern_substs(&[env_ty.into()]);
- let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs);
-
- let sig = sig.skip_binder();
- let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
- let state_adt_ref = tcx.adt_def(state_did);
- let state_substs = tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]);
- let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
- ty::Binder::bind_with_vars(
- tcx.mk_fn_sig(
- [env_ty, sig.resume_ty].iter(),
- &ret_ty,
- false,
- hir::Unsafety::Normal,
- rustc_target::spec::abi::Abi::Rust,
- ),
- bound_vars,
- )
- }
- _ => bug!("unexpected type {:?} in Instance::fn_sig", ty),
- }
- }
-}
-
/// Calculates whether a function's ABI can unwind or not.
///
/// This takes two primary parameters:
@@ -2996,40 +1095,6 @@ pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option<DefId>, abi: Spe
}
}
-#[inline]
-pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
- use rustc_target::spec::abi::Abi::*;
- match tcx.sess.target.adjust_abi(abi) {
- RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
- RustCold => Conv::RustCold,
-
- // It's the ABI's job to select this, not ours.
- System { .. } => bug!("system abi should be selected elsewhere"),
- EfiApi => bug!("eficall abi should be selected elsewhere"),
-
- Stdcall { .. } => Conv::X86Stdcall,
- Fastcall { .. } => Conv::X86Fastcall,
- Vectorcall { .. } => Conv::X86VectorCall,
- Thiscall { .. } => Conv::X86ThisCall,
- C { .. } => Conv::C,
- Unadjusted => Conv::C,
- Win64 { .. } => Conv::X86_64Win64,
- SysV64 { .. } => Conv::X86_64SysV,
- Aapcs { .. } => Conv::ArmAapcs,
- CCmseNonSecureCall => Conv::CCmseNonSecureCall,
- PtxKernel => Conv::PtxKernel,
- Msp430Interrupt => Conv::Msp430Intr,
- X86Interrupt => Conv::X86Intr,
- AmdGpuKernel => Conv::AmdGpuKernel,
- AvrInterrupt => Conv::AvrInterrupt,
- AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt,
- Wasm => Conv::C,
-
- // These API constants ought to be more specific...
- Cdecl { .. } => Conv::C,
- }
-}
-
/// Error produced by attempting to compute or adjust a `FnAbi`.
#[derive(Copy, Clone, Debug, HashStable)]
pub enum FnAbiError<'tcx> {
@@ -3061,6 +1126,12 @@ impl<'tcx> fmt::Display for FnAbiError<'tcx> {
}
}
+impl<'tcx> IntoDiagnostic<'tcx, !> for FnAbiError<'tcx> {
+ fn into_diagnostic(self, handler: &'tcx Handler) -> DiagnosticBuilder<'tcx, !> {
+ handler.struct_fatal(self.to_string())
+ }
+}
+
// FIXME(eddyb) maybe use something like this for an unified `fn_abi_of`, not
// just for error handling.
#[derive(Debug)]
@@ -3142,367 +1213,3 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
}
impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {}
-
-fn fn_abi_of_fn_ptr<'tcx>(
- tcx: TyCtxt<'tcx>,
- query: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
-) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
- let (param_env, (sig, extra_args)) = query.into_parts();
-
- LayoutCx { tcx, param_env }.fn_abi_new_uncached(sig, extra_args, None, None, false)
-}
-
-fn fn_abi_of_instance<'tcx>(
- tcx: TyCtxt<'tcx>,
- query: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
-) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
- let (param_env, (instance, extra_args)) = query.into_parts();
-
- let sig = instance.fn_sig_for_fn_abi(tcx, param_env);
-
- let caller_location = if instance.def.requires_caller_location(tcx) {
- Some(tcx.caller_location_ty())
- } else {
- None
- };
-
- LayoutCx { tcx, param_env }.fn_abi_new_uncached(
- sig,
- extra_args,
- caller_location,
- Some(instance.def_id()),
- matches!(instance.def, ty::InstanceDef::Virtual(..)),
- )
-}
-
-// Handle safe Rust thin and fat pointers.
-pub fn adjust_for_rust_scalar<'tcx>(
- cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
- attrs: &mut ArgAttributes,
- scalar: Scalar,
- layout: TyAndLayout<'tcx>,
- offset: Size,
- is_return: bool,
-) {
- // Booleans are always a noundef i1 that needs to be zero-extended.
- if scalar.is_bool() {
- attrs.ext(ArgExtension::Zext);
- attrs.set(ArgAttribute::NoUndef);
- return;
- }
-
- // Scalars which have invalid values cannot be undef.
- if !scalar.is_always_valid(&cx) {
- attrs.set(ArgAttribute::NoUndef);
- }
-
- // Only pointer types handled below.
- let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return };
-
- if !valid_range.contains(0) {
- attrs.set(ArgAttribute::NonNull);
- }
-
- if let Some(pointee) = layout.pointee_info_at(&cx, offset) {
- if let Some(kind) = pointee.safe {
- attrs.pointee_align = Some(pointee.align);
-
- // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable
- // for the entire duration of the function as they can be deallocated
- // at any time. Same for shared mutable references. If LLVM had a
- // way to say "dereferenceable on entry" we could use it here.
- attrs.pointee_size = match kind {
- PointerKind::UniqueBorrowed
- | PointerKind::UniqueBorrowedPinned
- | PointerKind::Frozen => pointee.size,
- PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO,
- };
-
- // `Box`, `&T`, and `&mut T` cannot be undef.
- // Note that this only applies to the value of the pointer itself;
- // this attribute doesn't make it UB for the pointed-to data to be undef.
- attrs.set(ArgAttribute::NoUndef);
-
- // The aliasing rules for `Box<T>` are still not decided, but currently we emit
- // `noalias` for it. This can be turned off using an unstable flag.
- // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326
- let noalias_for_box = cx.tcx.sess.opts.unstable_opts.box_noalias.unwrap_or(true);
-
- // `&mut` pointer parameters never alias other parameters,
- // or mutable global data
- //
- // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
- // and can be marked as both `readonly` and `noalias`, as
- // LLVM's definition of `noalias` is based solely on memory
- // dependencies rather than pointer equality
- //
- // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute
- // for UniqueBorrowed arguments, so that the codegen backend can decide whether
- // or not to actually emit the attribute. It can also be controlled with the
- // `-Zmutable-noalias` debugging option.
- let no_alias = match kind {
- PointerKind::SharedMutable
- | PointerKind::UniqueBorrowed
- | PointerKind::UniqueBorrowedPinned => false,
- PointerKind::UniqueOwned => noalias_for_box,
- PointerKind::Frozen => !is_return,
- };
- if no_alias {
- attrs.set(ArgAttribute::NoAlias);
- }
-
- if kind == PointerKind::Frozen && !is_return {
- attrs.set(ArgAttribute::ReadOnly);
- }
-
- if kind == PointerKind::UniqueBorrowed && !is_return {
- attrs.set(ArgAttribute::NoAliasMutRef);
- }
- }
- }
-}
-
-impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
- // FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
- // arguments of this method, into a separate `struct`.
- #[tracing::instrument(
- level = "debug",
- skip(self, caller_location, fn_def_id, force_thin_self_ptr)
- )]
- fn fn_abi_new_uncached(
- &self,
- sig: ty::PolyFnSig<'tcx>,
- extra_args: &[Ty<'tcx>],
- caller_location: Option<Ty<'tcx>>,
- fn_def_id: Option<DefId>,
- // FIXME(eddyb) replace this with something typed, like an `enum`.
- force_thin_self_ptr: bool,
- ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
- let sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, sig);
-
- let conv = conv_from_spec_abi(self.tcx(), sig.abi);
-
- let mut inputs = sig.inputs();
- let extra_args = if sig.abi == RustCall {
- assert!(!sig.c_variadic && extra_args.is_empty());
-
- if let Some(input) = sig.inputs().last() {
- if let ty::Tuple(tupled_arguments) = input.kind() {
- inputs = &sig.inputs()[0..sig.inputs().len() - 1];
- tupled_arguments
- } else {
- bug!(
- "argument to function with \"rust-call\" ABI \
- is not a tuple"
- );
- }
- } else {
- bug!(
- "argument to function with \"rust-call\" ABI \
- is not a tuple"
- );
- }
- } else {
- assert!(sig.c_variadic || extra_args.is_empty());
- extra_args
- };
-
- let target = &self.tcx.sess.target;
- let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl" | "uclibc");
- let win_x64_gnu = target.os == "windows" && target.arch == "x86_64" && target.env == "gnu";
- let linux_s390x_gnu_like =
- target.os == "linux" && target.arch == "s390x" && target_env_gnu_like;
- let linux_sparc64_gnu_like =
- target.os == "linux" && target.arch == "sparc64" && target_env_gnu_like;
- let linux_powerpc_gnu_like =
- target.os == "linux" && target.arch == "powerpc" && target_env_gnu_like;
- use SpecAbi::*;
- let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
-
- 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 layout = self.layout_of(ty)?;
- let layout = if force_thin_self_ptr && arg_idx == Some(0) {
- // Don't pass the vtable, it's not an argument of the virtual fn.
- // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
- // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
- make_thin_self_ptr(self, layout)
- } else {
- layout
- };
-
- let mut arg = ArgAbi::new(self, layout, |layout, scalar, offset| {
- let mut attrs = ArgAttributes::new();
- adjust_for_rust_scalar(*self, &mut attrs, scalar, *layout, offset, is_return);
- attrs
- });
-
- if arg.layout.is_zst() {
- // For some forsaken reason, x86_64-pc-windows-gnu
- // doesn't ignore zero-sized struct arguments.
- // The same is true for {s390x,sparc64,powerpc}-unknown-linux-{gnu,musl,uclibc}.
- if is_return
- || rust_abi
- || (!win_x64_gnu
- && !linux_s390x_gnu_like
- && !linux_sparc64_gnu_like
- && !linux_powerpc_gnu_like)
- {
- arg.mode = PassMode::Ignore;
- }
- }
-
- Ok(arg)
- };
-
- let mut fn_abi = FnAbi {
- ret: arg_of(sig.output(), None)?,
- args: inputs
- .iter()
- .copied()
- .chain(extra_args.iter().copied())
- .chain(caller_location)
- .enumerate()
- .map(|(i, ty)| arg_of(ty, Some(i)))
- .collect::<Result<_, _>>()?,
- c_variadic: sig.c_variadic,
- fixed_count: inputs.len() as u32,
- conv,
- can_unwind: fn_can_unwind(self.tcx(), fn_def_id, sig.abi),
- };
- self.fn_abi_adjust_for_abi(&mut fn_abi, sig.abi)?;
- debug!("fn_abi_new_uncached = {:?}", fn_abi);
- Ok(self.tcx.arena.alloc(fn_abi))
- }
-
- #[tracing::instrument(level = "trace", skip(self))]
- fn fn_abi_adjust_for_abi(
- &self,
- fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>,
- abi: SpecAbi,
- ) -> Result<(), FnAbiError<'tcx>> {
- if abi == SpecAbi::Unadjusted {
- return Ok(());
- }
-
- if abi == SpecAbi::Rust
- || abi == SpecAbi::RustCall
- || abi == SpecAbi::RustIntrinsic
- || abi == SpecAbi::PlatformIntrinsic
- {
- let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>| {
- if arg.is_ignore() {
- return;
- }
-
- match arg.layout.abi {
- Abi::Aggregate { .. } => {}
-
- // This is a fun case! The gist of what this is doing is
- // that we want callers and callees to always agree on the
- // ABI of how they pass SIMD arguments. If we were to *not*
- // make these arguments indirect then they'd be immediates
- // in LLVM, which means that they'd used whatever the
- // appropriate ABI is for the callee and the caller. That
- // means, for example, if the caller doesn't have AVX
- // enabled but the callee does, then passing an AVX argument
- // across this boundary would cause corrupt data to show up.
- //
- // This problem is fixed by unconditionally passing SIMD
- // arguments through memory between callers and callees
- // which should get them all to agree on ABI regardless of
- // target feature sets. Some more information about this
- // issue can be found in #44367.
- //
- // Note that the platform intrinsic ABI is exempt here as
- // that's how we connect up to LLVM and it's unstable
- // anyway, we control all calls to it in libstd.
- Abi::Vector { .. }
- if abi != SpecAbi::PlatformIntrinsic
- && self.tcx.sess.target.simd_types_indirect =>
- {
- arg.make_indirect();
- return;
- }
-
- _ => return,
- }
-
- let size = arg.layout.size;
- if arg.layout.is_unsized() || size > Pointer.size(self) {
- arg.make_indirect();
- } else {
- // We want to pass small aggregates as immediates, but using
- // a LLVM aggregate type for this leads to bad optimizations,
- // so we pick an appropriately sized integer type instead.
- arg.cast_to(Reg { kind: RegKind::Integer, size });
- }
- };
- fixup(&mut fn_abi.ret);
- for arg in fn_abi.args.iter_mut() {
- fixup(arg);
- }
- } else {
- fn_abi.adjust_for_foreign_abi(self, abi)?;
- }
-
- Ok(())
- }
-}
-
-#[tracing::instrument(level = "debug", skip(cx))]
-fn make_thin_self_ptr<'tcx>(
- cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>),
- layout: TyAndLayout<'tcx>,
-) -> TyAndLayout<'tcx> {
- let tcx = cx.tcx();
- let fat_pointer_ty = if layout.is_unsized() {
- // unsized `self` is passed as a pointer to `self`
- // FIXME (mikeyhew) change this to use &own if it is ever added to the language
- tcx.mk_mut_ptr(layout.ty)
- } else {
- match layout.abi {
- Abi::ScalarPair(..) | Abi::Scalar(..) => (),
- _ => bug!("receiver type has unsupported layout: {:?}", layout),
- }
-
- // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
- // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
- // elsewhere in the compiler as a method on a `dyn Trait`.
- // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
- // get a built-in pointer type
- let mut fat_pointer_layout = layout;
- 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
- && !fat_pointer_layout.ty.is_region_ptr()
- {
- for i in 0..fat_pointer_layout.fields.count() {
- let field_layout = fat_pointer_layout.field(cx, i);
-
- if !field_layout.is_zst() {
- fat_pointer_layout = field_layout;
- continue 'descend_newtypes;
- }
- }
-
- bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout);
- }
-
- fat_pointer_layout.ty
- };
-
- // we now have a type like `*mut RcBox<dyn Trait>`
- // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
- // this is understood as a special case elsewhere in the compiler
- let unit_ptr_ty = tcx.mk_mut_ptr(tcx.mk_unit());
-
- TyAndLayout {
- ty: fat_pointer_ty,
-
- // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing the `Result`
- // should always work because the type is always `*mut ()`.
- ..tcx.layout_of(ty::ParamEnv::reveal_all().and(unit_ptr_ty)).unwrap()
- }
-}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 3f9871190..a42d05706 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -17,7 +17,7 @@ pub use self::IntVarValue::*;
pub use self::Variance::*;
use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
use crate::metadata::ModChild;
-use crate::middle::privacy::AccessLevels;
+use crate::middle::privacy::EffectiveVisibilities;
use crate::mir::{Body, GeneratorLayout};
use crate::traits::{self, Reveal};
use crate::ty;
@@ -26,6 +26,7 @@ use crate::ty::util::Discr;
pub use adt::*;
pub use assoc::*;
pub use generics::*;
+use hir::OpaqueTyOrigin;
use rustc_ast as ast;
use rustc_ast::node_id::NodeMap;
use rustc_attr as attr;
@@ -37,11 +38,13 @@ use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, LifetimeRes, Res};
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap};
+use rustc_hir::definitions::Definitions;
use rustc_hir::Node;
use rustc_index::vec::IndexVec;
use rustc_macros::HashStable;
use rustc_query_system::ich::StableHashingContext;
use rustc_serialize::{Decodable, Encodable};
+use rustc_session::cstore::CrateStoreDyn;
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{ExpnId, Span};
@@ -73,11 +76,11 @@ pub use self::closure::{
CAPTURE_STRUCT_LOCAL,
};
pub use self::consts::{
- Const, ConstInt, ConstKind, ConstS, InferConst, ScalarInt, Unevaluated, ValTree,
+ Const, ConstInt, ConstKind, ConstS, InferConst, ScalarInt, UnevaluatedConst, ValTree,
};
pub use self::context::{
tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
- CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData,
+ CtxtInterners, DeducedParamAttrs, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData,
GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType,
UserTypeAnnotationIndex,
};
@@ -89,9 +92,9 @@ pub use self::sty::BoundRegionKind::*;
pub use self::sty::{
Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid,
- EarlyBinder, EarlyBoundRegion, ExistentialPredicate, ExistentialProjection,
- ExistentialTraitRef, FnSig, FreeRegion, GenSig, GeneratorSubsts, GeneratorSubstsParts,
- InlineConstSubsts, InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
+ EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
+ FreeRegion, GenSig, GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts,
+ InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind,
RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo,
};
@@ -130,8 +133,8 @@ mod erase_regions;
mod generics;
mod impls_ty;
mod instance;
-mod layout_sanity_check;
mod list;
+mod opaque_types;
mod parameterized;
mod rvalue_scopes;
mod structural_impls;
@@ -141,8 +144,15 @@ mod sty;
pub type RegisteredTools = FxHashSet<Ident>;
-#[derive(Debug)]
pub struct ResolverOutputs {
+ pub definitions: Definitions,
+ pub global_ctxt: ResolverGlobalCtxt,
+ pub ast_lowering: ResolverAstLowering,
+}
+
+#[derive(Debug)]
+pub struct ResolverGlobalCtxt {
+ pub cstore: Box<CrateStoreDyn>,
pub visibilities: FxHashMap<LocalDefId, Visibility>,
/// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error.
pub has_pub_restricted: bool,
@@ -150,7 +160,7 @@ pub struct ResolverOutputs {
pub expn_that_defined: FxHashMap<LocalDefId, ExpnId>,
/// Reference span for definitions.
pub source_span: IndexVec<LocalDefId, Span>,
- pub access_levels: AccessLevels,
+ pub effective_visibilities: EffectiveVisibilities,
pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
@@ -682,7 +692,7 @@ pub enum PredicateKind<'tcx> {
Coerce(CoercePredicate<'tcx>),
/// Constant initializer must evaluate successfully.
- ConstEvaluatable(ty::Unevaluated<'tcx, ()>),
+ ConstEvaluatable(ty::Const<'tcx>),
/// Constants must be equal. The first component is the const that is expected.
ConstEquate(Const<'tcx>, Const<'tcx>),
@@ -861,6 +871,11 @@ impl<'tcx> TraitPredicate<'tcx> {
(BoundConstness::ConstIfConst, hir::Constness::NotConst) => false,
}
}
+
+ pub fn without_const(mut self) -> Self {
+ self.constness = BoundConstness::NotConst;
+ self
+ }
}
impl<'tcx> PolyTraitPredicate<'tcx> {
@@ -1296,6 +1311,106 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
sub: sub_diag,
});
}
+
+ #[instrument(level = "debug", skip(tcx), ret)]
+ pub fn remap_generic_params_to_declaration_params(
+ self,
+ opaque_type_key: OpaqueTypeKey<'tcx>,
+ tcx: TyCtxt<'tcx>,
+ // typeck errors have subpar spans for opaque types, so delay error reporting until borrowck.
+ ignore_errors: bool,
+ origin: OpaqueTyOrigin,
+ ) -> Self {
+ let OpaqueTypeKey { def_id, substs } = opaque_type_key;
+
+ // Use substs to build up a reverse map from regions to their
+ // identity mappings. This is necessary because of `impl
+ // Trait` lifetimes are computed by replacing existing
+ // lifetimes with 'static and remapping only those used in the
+ // `impl Trait` return type, resulting in the parameters
+ // shifting.
+ let id_substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+ debug!(?id_substs);
+
+ let map = substs.iter().zip(id_substs);
+
+ let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = match origin {
+ // HACK: The HIR lowering for async fn does not generate
+ // any `+ Captures<'x>` bounds for the `impl Future<...>`, so all async fns with lifetimes
+ // would now fail to compile. We should probably just make hir lowering fill this in properly.
+ OpaqueTyOrigin::AsyncFn(_) => map.collect(),
+ OpaqueTyOrigin::FnReturn(_) | OpaqueTyOrigin::TyAlias => {
+ // Opaque types may only use regions that are bound. So for
+ // ```rust
+ // type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
+ // ```
+ // we may not use `'c` in the hidden type.
+ struct OpaqueTypeLifetimeCollector<'tcx> {
+ lifetimes: FxHashSet<ty::Region<'tcx>>,
+ }
+
+ impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> {
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ self.lifetimes.insert(r);
+ r.super_visit_with(self)
+ }
+ }
+
+ let mut collector = OpaqueTypeLifetimeCollector { lifetimes: Default::default() };
+
+ for pred in tcx.bound_explicit_item_bounds(def_id.to_def_id()).transpose_iter() {
+ let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs);
+
+ trace!(pred=?pred.kind());
+
+ // We only ignore opaque type substs if the opaque type is the outermost type.
+ // The opaque type may be nested within itself via recursion in e.g.
+ // type Foo<'a> = impl PartialEq<Foo<'a>>;
+ // which thus mentions `'a` and should thus accept hidden types that borrow 'a
+ // instead of requiring an additional `+ 'a`.
+ match pred.kind().skip_binder() {
+ ty::PredicateKind::Trait(TraitPredicate {
+ trait_ref: ty::TraitRef { def_id: _, substs },
+ constness: _,
+ polarity: _,
+ }) => {
+ trace!(?substs);
+ for subst in &substs[1..] {
+ subst.visit_with(&mut collector);
+ }
+ }
+ ty::PredicateKind::Projection(ty::ProjectionPredicate {
+ projection_ty: ty::ProjectionTy { substs, item_def_id: _ },
+ term,
+ }) => {
+ for subst in &substs[1..] {
+ subst.visit_with(&mut collector);
+ }
+ term.visit_with(&mut collector);
+ }
+ _ => {
+ pred.visit_with(&mut collector);
+ }
+ }
+ }
+ let lifetimes = collector.lifetimes;
+ trace!(?lifetimes);
+ map.filter(|(_, v)| {
+ let ty::GenericArgKind::Lifetime(lt) = v.unpack() else {
+ return true;
+ };
+ lifetimes.contains(&lt)
+ })
+ .collect()
+ }
+ };
+ debug!("map = {:#?}", map);
+
+ // Convert the type from the function into a type valid outside
+ // the function, by replacing invalid regions with 'static,
+ // after producing an error for each of them.
+ self.fold_with(&mut opaque_types::ReverseMapper::new(tcx, map, self.span, ignore_errors))
+ }
}
/// The "placeholder index" fully defines a placeholder region, type, or const. Placeholders are
@@ -2590,7 +2705,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
closure::provide(providers);
context::provide(providers);
erase_regions::provide(providers);
- layout::provide(providers);
+ inhabitedness::provide(providers);
util::provide(providers);
print::provide(providers);
super::util::bug::provide(providers);
@@ -2598,7 +2713,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers {
trait_impls_of: trait_def::trait_impls_of_provider,
incoherent_impls: trait_def::incoherent_impls_provider,
- type_uninhabited_from: inhabitedness::type_uninhabited_from,
const_param_default: consts::const_param_default,
vtable_allocation: vtable::vtable_allocation_provider,
..*providers
@@ -2667,8 +2781,9 @@ pub struct DestructuredConst<'tcx> {
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;
- // These are in alphabetical order, which is easy to maintain.
+ // tidy-alphabetical-start
static_assert_size!(PredicateS<'_>, 48);
static_assert_size!(TyS<'_>, 40);
static_assert_size!(WithStableHash<TyS<'_>>, 56);
+ // tidy-alphabetical-end
}
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 9db5a2894..ee13920d5 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -10,8 +10,7 @@
use crate::mir;
use crate::traits::query::NoSolution;
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder};
-use crate::ty::subst::{Subst, SubstsRef};
-use crate::ty::{self, EarlyBinder, Ty, TyCtxt};
+use crate::ty::{self, EarlyBinder, SubstsRef, Ty, TyCtxt};
#[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)]
pub enum NormalizationError<'tcx> {
@@ -215,15 +214,6 @@ impl<'tcx> TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const()
}
-
- #[inline]
- fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
- // FIXME: This *probably* needs canonicalization too!
- let arg = self.param_env.and(c);
- self.tcx
- .try_normalize_mir_const_after_erasing_regions(arg)
- .unwrap_or_else(|_| bug!("failed to normalize {:?}", c))
- }
}
struct TryNormalizeAfterErasingRegionsFolder<'tcx> {
@@ -268,16 +258,4 @@ impl<'tcx> FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'t
Err(_) => Err(NormalizationError::Const(c)),
}
}
-
- fn try_fold_mir_const(
- &mut self,
- c: mir::ConstantKind<'tcx>,
- ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
- // FIXME: This *probably* needs canonicalization too!
- let arg = self.param_env.and(c);
- match self.tcx.try_normalize_mir_const_after_erasing_regions(arg) {
- Ok(c) => Ok(c),
- Err(_) => Err(NormalizationError::ConstantKind(c)),
- }
- }
}
diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs
new file mode 100644
index 000000000..b05c63109
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/opaque_types.rs
@@ -0,0 +1,218 @@
+use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc_span::Span;
+
+/// Converts generic params of a TypeFoldable from one
+/// item's generics to another. Usually from a function's generics
+/// list to the opaque type's own generics.
+pub(super) struct ReverseMapper<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
+ /// see call sites to fold_kind_no_missing_regions_error
+ /// for an explanation of this field.
+ do_not_error: bool,
+
+ /// We do not want to emit any errors in typeck because
+ /// the spans in typeck are subpar at the moment.
+ /// Borrowck will do the same work again (this time with
+ /// lifetime information) and thus report better errors.
+ ignore_errors: bool,
+
+ /// Span of function being checked.
+ span: Span,
+}
+
+impl<'tcx> ReverseMapper<'tcx> {
+ pub(super) fn new(
+ tcx: TyCtxt<'tcx>,
+ map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
+ span: Span,
+ ignore_errors: bool,
+ ) -> Self {
+ Self { tcx, map, do_not_error: false, ignore_errors, span }
+ }
+
+ fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
+ assert!(!self.do_not_error);
+ self.do_not_error = true;
+ let kind = kind.fold_with(self);
+ self.do_not_error = false;
+ kind
+ }
+
+ fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
+ assert!(!self.do_not_error);
+ kind.fold_with(self)
+ }
+}
+
+impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ match *r {
+ // Ignore bound regions and `'static` regions that appear in the
+ // type, we only need to remap regions that reference lifetimes
+ // from the function declaration.
+ // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
+ ty::ReLateBound(..) | ty::ReStatic => return r,
+
+ // If regions have been erased (by writeback), don't try to unerase
+ // them.
+ ty::ReErased => return r,
+
+ // The regions that we expect from borrow checking.
+ ty::ReEarlyBound(_) | ty::ReFree(_) => {}
+
+ ty::RePlaceholder(_) | ty::ReVar(_) => {
+ // All of the regions in the type should either have been
+ // erased by writeback, or mapped back to named regions by
+ // borrow checking.
+ bug!("unexpected region kind in opaque type: {:?}", r);
+ }
+ }
+
+ match self.map.get(&r.into()).map(|k| k.unpack()) {
+ Some(GenericArgKind::Lifetime(r1)) => r1,
+ Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
+ None if self.do_not_error => self.tcx.lifetimes.re_static,
+ None => {
+ self.tcx
+ .sess
+ .struct_span_err(self.span, "non-defining opaque type use in defining scope")
+ .span_label(
+ self.span,
+ format!(
+ "lifetime `{}` is part of concrete type but not used in \
+ parameter list of the `impl Trait` type alias",
+ r
+ ),
+ )
+ .emit();
+
+ self.tcx().lifetimes.re_static
+ }
+ }
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ match *ty.kind() {
+ ty::Closure(def_id, substs) => {
+ // I am a horrible monster and I pray for death. When
+ // we encounter a closure here, it is always a closure
+ // from within the function that we are currently
+ // type-checking -- one that is now being encapsulated
+ // in an opaque type. Ideally, we would
+ // go through the types/lifetimes that it references
+ // and treat them just like we would any other type,
+ // which means we would error out if we find any
+ // reference to a type/region that is not in the
+ // "reverse map".
+ //
+ // **However,** in the case of closures, there is a
+ // somewhat subtle (read: hacky) consideration. The
+ // problem is that our closure types currently include
+ // all the lifetime parameters declared on the
+ // enclosing function, even if they are unused by the
+ // closure itself. We can't readily filter them out,
+ // so here we replace those values with `'empty`. This
+ // can't really make a difference to the rest of the
+ // compiler; those regions are ignored for the
+ // outlives relation, and hence don't affect trait
+ // selection or auto traits, and they are erased
+ // during codegen.
+
+ let generics = self.tcx.generics_of(def_id);
+ let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
+ if index < generics.parent_count {
+ // Accommodate missing regions in the parent kinds...
+ self.fold_kind_no_missing_regions_error(kind)
+ } else {
+ // ...but not elsewhere.
+ self.fold_kind_normally(kind)
+ }
+ }));
+
+ self.tcx.mk_closure(def_id, substs)
+ }
+
+ ty::Generator(def_id, substs, movability) => {
+ let generics = self.tcx.generics_of(def_id);
+ let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
+ if index < generics.parent_count {
+ // Accommodate missing regions in the parent kinds...
+ self.fold_kind_no_missing_regions_error(kind)
+ } else {
+ // ...but not elsewhere.
+ self.fold_kind_normally(kind)
+ }
+ }));
+
+ self.tcx.mk_generator(def_id, substs, movability)
+ }
+
+ ty::Param(param) => {
+ // Look it up in the substitution list.
+ match self.map.get(&ty.into()).map(|k| k.unpack()) {
+ // Found it in the substitution list; replace with the parameter from the
+ // opaque type.
+ Some(GenericArgKind::Type(t1)) => t1,
+ Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
+ None => {
+ debug!(?param, ?self.map);
+ if !self.ignore_errors {
+ self.tcx
+ .sess
+ .struct_span_err(
+ self.span,
+ &format!(
+ "type parameter `{}` is part of concrete type but not \
+ used in parameter list for the `impl Trait` type alias",
+ ty
+ ),
+ )
+ .emit();
+ }
+
+ self.tcx().ty_error()
+ }
+ }
+ }
+
+ _ => ty.super_fold_with(self),
+ }
+ }
+
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ trace!("checking const {:?}", ct);
+ // Find a const parameter
+ match ct.kind() {
+ ty::ConstKind::Param(..) => {
+ // Look it up in the substitution list.
+ match self.map.get(&ct.into()).map(|k| k.unpack()) {
+ // Found it in the substitution list, replace with the parameter from the
+ // opaque type.
+ Some(GenericArgKind::Const(c1)) => c1,
+ Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
+ None => {
+ if !self.ignore_errors {
+ self.tcx.sess.emit_err(ty::ConstNotUsedTraitAlias {
+ ct: ct.to_string(),
+ span: self.span,
+ });
+ }
+
+ self.tcx().const_error(ct.ty())
+ }
+ }
+ }
+
+ _ => ct,
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index 9c8dc30e2..e1e705a92 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -1,3 +1,4 @@
+use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::{DefId, DefIndex};
use rustc_index::vec::{Idx, IndexVec};
@@ -29,6 +30,10 @@ impl<I: Idx + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for IndexVe
type Value<'tcx> = IndexVec<I, T::Value<'tcx>>;
}
+impl<I: 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for FxHashMap<I, T> {
+ type Value<'tcx> = FxHashMap<I, T::Value<'tcx>>;
+}
+
impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::Binder<'static, T> {
type Value<'tcx> = ty::Binder<'tcx, T::Value<'tcx>>;
}
@@ -56,6 +61,7 @@ trivially_parameterized_over_tcx! {
crate::middle::resolve_lifetime::ObjectLifetimeDefault,
crate::mir::ConstQualifs,
ty::AssocItemContainer,
+ ty::DeducedParamAttrs,
ty::Generics,
ty::ImplPolarity,
ty::ReprOptions,
@@ -77,6 +83,7 @@ trivially_parameterized_over_tcx! {
rustc_hir::def::DefKind,
rustc_hir::def_id::DefIndex,
rustc_hir::definitions::DefKey,
+ rustc_index::bit_set::BitSet<u32>,
rustc_index::bit_set::FiniteBitSet<u32>,
rustc_session::cstore::ForeignModule,
rustc_session::cstore::LinkagePreference,
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index d57cf8f01..44b9548db 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -1,9 +1,9 @@
-use crate::ty::subst::{GenericArg, Subst};
+use crate::ty::GenericArg;
use crate::ty::{self, DefIdTree, Ty, TyCtxt};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sso::SsoHashSet;
-use rustc_hir::def_id::{CrateNum, DefId};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
// `pretty` is a separate module only for organization.
@@ -325,3 +325,12 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> {
cx.print_const(*self)
}
}
+
+// This is only used by query descriptions
+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()))
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 97bddb93e..ef9aa236b 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1,9 +1,9 @@
use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
-use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
use crate::ty::{
self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, TermKind, Ty, TyCtxt, TypeFoldable,
TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
};
+use crate::ty::{GenericArg, GenericArgKind};
use rustc_apfloat::ieee::{Double, Single};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_data_structures::sso::SsoHashSet;
@@ -16,6 +16,7 @@ use rustc_session::cstore::{ExternCrate, ExternCrateSource};
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_target::abi::Size;
use rustc_target::spec::abi::Abi;
+use smallvec::SmallVec;
use std::cell::Cell;
use std::char;
@@ -62,6 +63,7 @@ thread_local! {
static NO_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };
static NO_QUERIES: Cell<bool> = const { Cell::new(false) };
static NO_VISIBLE_PATH: Cell<bool> = const { Cell::new(false) };
+ static NO_VERBOSE_CONSTANTS: Cell<bool> = const { Cell::new(false) };
}
macro_rules! define_helper {
@@ -116,6 +118,9 @@ define_helper!(
/// Prevent selection of visible paths. `Display` impl of DefId will prefer
/// visible (public) reexports of types as paths.
fn with_no_visible_paths(NoVisibleGuard, NO_VISIBLE_PATH);
+ /// Prevent verbose printing of constants. Verbose printing of constants is
+ /// never desirable in some contexts like `std::any::type_name`.
+ fn with_no_verbose_constants(NoVerboseConstantsGuard, NO_VERBOSE_CONSTANTS);
);
/// The "region highlights" are used to control region printing during
@@ -637,7 +642,9 @@ pub trait PrettyPrinter<'tcx>:
p!(print_def_path(def_id, &[]));
}
ty::Projection(ref data) => {
- if self.tcx().def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder {
+ if !(self.tcx().sess.verbose() || NO_QUERIES.with(|q| q.get()))
+ && self.tcx().def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder
+ {
return self.pretty_print_opaque_impl_type(data.item_def_id, data.substs);
} else {
p!(print(data))
@@ -756,7 +763,7 @@ pub trait PrettyPrinter<'tcx>:
}
ty::Array(ty, sz) => {
p!("[", print(ty), "; ");
- if self.tcx().sess.verbose() {
+ if !NO_VERBOSE_CONSTANTS.with(|flag| flag.get()) && self.tcx().sess.verbose() {
p!(write("{:?}", sz));
} else if let ty::ConstKind::Unevaluated(..) = sz.kind() {
// Do not try to evaluate unevaluated constants. If we are const evaluating an
@@ -792,9 +799,9 @@ pub trait PrettyPrinter<'tcx>:
let mut traits = FxIndexMap::default();
let mut fn_traits = FxIndexMap::default();
let mut is_sized = false;
+ let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new();
- for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
- let predicate = predicate.subst(tcx, substs);
+ for (predicate, _) in bounds.subst_iter_copied(tcx, substs) {
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
@@ -823,6 +830,9 @@ pub trait PrettyPrinter<'tcx>:
&mut fn_traits,
);
}
+ ty::PredicateKind::TypeOutlives(outlives) => {
+ lifetimes.push(outlives.1);
+ }
_ => {}
}
}
@@ -927,7 +937,7 @@ pub trait PrettyPrinter<'tcx>:
// unless we can find out what generator return type it comes from.
let term = if let Some(ty) = term.skip_binder().ty()
&& let ty::Projection(proj) = ty.kind()
- && let assoc = tcx.associated_item(proj.item_def_id)
+ && let Some(assoc) = tcx.opt_associated_item(proj.item_def_id)
&& assoc.trait_container(tcx) == tcx.lang_items().gen_trait()
&& assoc.name == rustc_span::sym::Return
{
@@ -976,6 +986,11 @@ pub trait PrettyPrinter<'tcx>:
write!(self, "Sized")?;
}
+ for re in lifetimes {
+ write!(self, " + ")?;
+ self = self.print_region(re)?;
+ }
+
Ok(self)
}
@@ -1088,17 +1103,9 @@ pub trait PrettyPrinter<'tcx>:
.generics_of(principal.def_id)
.own_substs_no_defaults(cx.tcx(), principal.substs);
- // Don't print `'_` if there's no unerased regions.
- let print_regions = args.iter().any(|arg| match arg.unpack() {
- GenericArgKind::Lifetime(r) => !r.is_erased(),
- _ => false,
- });
- let mut args = args.iter().cloned().filter(|arg| match arg.unpack() {
- GenericArgKind::Lifetime(_) => print_regions,
- _ => true,
- });
let mut projections = predicates.projection_bounds();
+ let mut args = args.iter().cloned();
let arg0 = args.next();
let projection0 = projections.next();
if arg0.is_some() || projection0.is_some() {
@@ -1178,7 +1185,7 @@ pub trait PrettyPrinter<'tcx>:
) -> Result<Self::Const, Self::Error> {
define_scoped_cx!(self);
- if self.tcx().sess.verbose() {
+ if !NO_VERBOSE_CONSTANTS.with(|flag| flag.get()) && self.tcx().sess.verbose() {
p!(write("Const({:?}: {:?})", ct.kind(), ct.ty()));
return Ok(self);
}
@@ -1201,9 +1208,7 @@ pub trait PrettyPrinter<'tcx>:
}
match ct.kind() {
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
- assert_eq!(promoted, ());
-
+ ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
match self.tcx().def_kind(def.did) {
DefKind::Static(..) | DefKind::Const | DefKind::AssocConst => {
p!(print_value_path(def.did, substs))
@@ -1415,7 +1420,7 @@ pub trait PrettyPrinter<'tcx>:
) -> Result<Self::Const, Self::Error> {
define_scoped_cx!(self);
- if self.tcx().sess.verbose() {
+ if !NO_VERBOSE_CONSTANTS.with(|flag| flag.get()) && self.tcx().sess.verbose() {
p!(write("ValTree({:?}: ", valtree), print(ty), ")");
return Ok(self);
}
@@ -1572,7 +1577,9 @@ pub struct FmtPrinterData<'a, 'tcx> {
in_value: bool,
pub print_alloc_ids: bool,
+ // set of all named (non-anonymous) region names
used_region_names: FxHashSet<Symbol>,
+
region_index: usize,
binder_depth: usize,
printed_type_count: usize,
@@ -1847,22 +1854,11 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
) -> Result<Self::Path, Self::Error> {
self = print_prefix(self)?;
- // Don't print `'_` if there's no unerased regions.
- let print_regions = self.tcx.sess.verbose()
- || args.iter().any(|arg| match arg.unpack() {
- GenericArgKind::Lifetime(r) => !r.is_erased(),
- _ => false,
- });
- let args = args.iter().cloned().filter(|arg| match arg.unpack() {
- GenericArgKind::Lifetime(_) => print_regions,
- _ => true,
- });
-
- if args.clone().next().is_some() {
+ if args.first().is_some() {
if self.in_value {
write!(self, "::")?;
}
- self.generic_delimiters(|cx| cx.comma_sep(args))
+ self.generic_delimiters(|cx| cx.comma_sep(args.iter().cloned()))
} else {
Ok(self)
}
@@ -2074,7 +2070,14 @@ struct RegionFolder<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
current_index: ty::DebruijnIndex,
region_map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
- name: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
+ name: &'a mut (
+ dyn FnMut(
+ Option<ty::DebruijnIndex>, // Debruijn index of the folded late-bound region
+ ty::DebruijnIndex, // Index corresponding to binder level
+ ty::BoundRegion,
+ ) -> ty::Region<'tcx>
+ + 'a
+ ),
}
impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
@@ -2105,7 +2108,9 @@ impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
let name = &mut self.name;
let region = match *r {
- ty::ReLateBound(_, br) => *self.region_map.entry(br).or_insert_with(|| name(br)),
+ ty::ReLateBound(db, br) if db >= self.current_index => {
+ *self.region_map.entry(br).or_insert_with(|| name(Some(db), self.current_index, br))
+ }
ty::RePlaceholder(ty::PlaceholderRegion { name: kind, .. }) => {
// If this is an anonymous placeholder, don't rename. Otherwise, in some
// async fns, we get a `for<'r> Send` bound
@@ -2114,7 +2119,10 @@ impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
_ => {
// Index doesn't matter, since this is just for naming and these never get bound
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
- *self.region_map.entry(br).or_insert_with(|| name(br))
+ *self
+ .region_map
+ .entry(br)
+ .or_insert_with(|| name(None, self.current_index, br))
}
}
}
@@ -2139,23 +2147,31 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
where
T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>,
{
- fn name_by_region_index(index: usize) -> Symbol {
- match index {
- 0 => Symbol::intern("'r"),
- 1 => Symbol::intern("'s"),
- i => Symbol::intern(&format!("'t{}", i - 2)),
+ fn name_by_region_index(
+ index: usize,
+ available_names: &mut Vec<Symbol>,
+ num_available: usize,
+ ) -> Symbol {
+ if let Some(name) = available_names.pop() {
+ name
+ } else {
+ Symbol::intern(&format!("'z{}", index - num_available))
}
}
+ debug!("name_all_regions");
+
// Replace any anonymous late-bound regions with named
// variants, using new unique identifiers, so that we can
// clearly differentiate between named and unnamed regions in
// the output. We'll probably want to tweak this over time to
// decide just how much information to give.
if self.binder_depth == 0 {
- self.prepare_late_bound_region_info(value);
+ self.prepare_region_info(value);
}
+ debug!("self.used_region_names: {:?}", &self.used_region_names);
+
let mut empty = true;
let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| {
let w = if empty {
@@ -2172,13 +2188,30 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
define_scoped_cx!(self);
+ let possible_names =
+ ('a'..='z').rev().map(|s| Symbol::intern(&format!("'{s}"))).collect::<Vec<_>>();
+
+ let mut available_names = possible_names
+ .into_iter()
+ .filter(|name| !self.used_region_names.contains(&name))
+ .collect::<Vec<_>>();
+ debug!(?available_names);
+ let num_available = available_names.len();
+
let mut region_index = self.region_index;
- let mut next_name = |this: &Self| loop {
- let name = name_by_region_index(region_index);
- region_index += 1;
- if !this.used_region_names.contains(&name) {
- break name;
+ let mut next_name = |this: &Self| {
+ let mut name;
+
+ loop {
+ name = name_by_region_index(region_index, &mut available_names, num_available);
+ region_index += 1;
+
+ if !this.used_region_names.contains(&name) {
+ break;
+ }
}
+
+ name
};
// If we want to print verbosely, then print *all* binders, even if they
@@ -2199,6 +2232,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
ty::BrAnon(_) | ty::BrEnv => {
start_or_continue(&mut self, "for<", ", ");
let name = next_name(&self);
+ debug!(?name);
do_continue(&mut self, name);
ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
}
@@ -2227,24 +2261,63 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
})
} else {
let tcx = self.tcx;
- let mut name = |br: ty::BoundRegion| {
- start_or_continue(&mut self, "for<", ", ");
- let kind = match br.kind {
+
+ // Closure used in `RegionFolder` to create names for anonymous late-bound
+ // regions. We use two `DebruijnIndex`es (one for the currently folded
+ // late-bound region and the other for the binder level) to determine
+ // whether a name has already been created for the currently folded region,
+ // see issue #102392.
+ let mut name = |lifetime_idx: Option<ty::DebruijnIndex>,
+ binder_level_idx: ty::DebruijnIndex,
+ br: ty::BoundRegion| {
+ let (name, kind) = match br.kind {
ty::BrAnon(_) | ty::BrEnv => {
let name = next_name(&self);
- do_continue(&mut self, name);
- ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
+
+ if let Some(lt_idx) = lifetime_idx {
+ if lt_idx > binder_level_idx {
+ let kind = ty::BrNamed(CRATE_DEF_ID.to_def_id(), name);
+ return tcx.mk_region(ty::ReLateBound(
+ ty::INNERMOST,
+ ty::BoundRegion { var: br.var, kind },
+ ));
+ }
+ }
+
+ (name, ty::BrNamed(CRATE_DEF_ID.to_def_id(), name))
}
ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
let name = next_name(&self);
- do_continue(&mut self, name);
- ty::BrNamed(def_id, name)
+
+ if let Some(lt_idx) = lifetime_idx {
+ if lt_idx > binder_level_idx {
+ let kind = ty::BrNamed(def_id, name);
+ return tcx.mk_region(ty::ReLateBound(
+ ty::INNERMOST,
+ ty::BoundRegion { var: br.var, kind },
+ ));
+ }
+ }
+
+ (name, ty::BrNamed(def_id, name))
}
ty::BrNamed(_, name) => {
- do_continue(&mut self, name);
- br.kind
+ if let Some(lt_idx) = lifetime_idx {
+ if lt_idx > binder_level_idx {
+ let kind = br.kind;
+ return tcx.mk_region(ty::ReLateBound(
+ ty::INNERMOST,
+ ty::BoundRegion { var: br.var, kind },
+ ));
+ }
+ }
+
+ (name, br.kind)
}
};
+
+ start_or_continue(&mut self, "for<", ", ");
+ do_continue(&mut self, name);
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
};
let mut folder = RegionFolder {
@@ -2292,29 +2365,37 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
Ok(inner)
}
- fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>)
+ fn prepare_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>)
where
T: TypeVisitable<'tcx>,
{
- struct LateBoundRegionNameCollector<'a, 'tcx> {
- used_region_names: &'a mut FxHashSet<Symbol>,
+ struct RegionNameCollector<'tcx> {
+ used_region_names: FxHashSet<Symbol>,
type_collector: SsoHashSet<Ty<'tcx>>,
}
- impl<'tcx> ty::visit::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> {
+ impl<'tcx> RegionNameCollector<'tcx> {
+ fn new() -> Self {
+ RegionNameCollector {
+ used_region_names: Default::default(),
+ type_collector: SsoHashSet::new(),
+ }
+ }
+ }
+
+ impl<'tcx> ty::visit::TypeVisitor<'tcx> for RegionNameCollector<'tcx> {
type BreakTy = ();
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
trace!("address: {:p}", r.0.0);
- if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r {
- self.used_region_names.insert(name);
- } else if let ty::RePlaceholder(ty::PlaceholderRegion {
- name: ty::BrNamed(_, name),
- ..
- }) = *r
- {
+
+ // Collect all named lifetimes. These allow us to prevent duplication
+ // of already existing lifetime names when introducing names for
+ // anonymous late-bound regions.
+ if let Some(name) = r.get_name() {
self.used_region_names.insert(name);
}
+
r.super_visit_with(self)
}
@@ -2330,12 +2411,9 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
}
}
- self.used_region_names.clear();
- let mut collector = LateBoundRegionNameCollector {
- used_region_names: &mut self.used_region_names,
- type_collector: SsoHashSet::new(),
- };
+ let mut collector = RegionNameCollector::new();
value.visit_with(&mut collector);
+ self.used_region_names = collector.used_region_names;
self.region_index = 0;
}
}
@@ -2637,8 +2715,8 @@ define_print_and_forward_display! {
print_value_path(closure_def_id, &[]),
write("` implements the trait `{}`", kind))
}
- ty::PredicateKind::ConstEvaluatable(uv) => {
- p!("the constant `", print_value_path(uv.def.did, uv.substs), "` can be evaluated")
+ ty::PredicateKind::ConstEvaluatable(ct) => {
+ p!("the constant `", print(ct), "` can be evaluated")
}
ty::PredicateKind::ConstEquate(c1, c2) => {
p!("the constant `", print(c1), "` equals `", print(c2), "`")
@@ -2662,7 +2740,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
// Iterate all local crate items no matter where they are defined.
let hir = tcx.hir();
for id in hir.items() {
- if matches!(tcx.def_kind(id.def_id), DefKind::Use) {
+ if matches!(tcx.def_kind(id.owner_id), DefKind::Use) {
continue;
}
@@ -2671,7 +2749,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
continue;
}
- let def_id = item.def_id.to_def_id();
+ let def_id = item.owner_id.to_def_id();
let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS);
collect_fn(&item.ident, ns, def_id);
}
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index a300a8df2..ec90590ad 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -1,11 +1,11 @@
use crate::dep_graph;
use crate::infer::canonical::{self, Canonical};
-use crate::lint::LintLevelMap;
+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::AccessLevels;
+use crate::middle::privacy::EffectiveVisibilities;
use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLifetimes};
use crate::middle::stability::{self, DeprecationEntry};
use crate::mir;
@@ -32,7 +32,7 @@ use crate::ty::layout::TyAndLayout;
use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::util::AlwaysRequiresDrop;
use crate::ty::GeneratorDiagnosticData;
-use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
+use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
use rustc_ast as ast;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_attr as attr;
@@ -40,17 +40,19 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::unord::UnordSet;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId};
+use rustc_hir::hir_id::OwnerId;
use rustc_hir::lang_items::{LangItem, LanguageItems};
use rustc_hir::{Crate, ItemLocalId, TraitCandidate};
use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
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::utils::NativeLibKind;
+use rustc_session::lint::LintExpectationId;
use rustc_session::Limits;
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
@@ -275,8 +277,9 @@ macro_rules! define_callbacks {
fn default() -> Self {
Providers {
$($name: |_, key| bug!(
- "`tcx.{}({:?})` unsupported by its crate; \
- perhaps the `{}` query was never assigned a provider function",
+ "`tcx.{}({:?})` is not supported for external or local crate;\n
+ hint: Queries can be either made to the local crate, or the external crate. This error means you tried to use it for one that's not supported (likely the local crate).\n
+ If that's not the case, {} was likely never assigned to a provider function.\n",
stringify!($name),
key,
stringify!($name),
@@ -335,7 +338,7 @@ macro_rules! define_callbacks {
rustc_query_append! { define_callbacks! }
mod sealed {
- use super::{DefId, LocalDefId};
+ use super::{DefId, LocalDefId, OwnerId};
/// An analogue of the `Into` trait that's intended only for query parameters.
///
@@ -365,6 +368,13 @@ mod sealed {
self.to_def_id()
}
}
+
+ impl IntoQueryParam<DefId> for OwnerId {
+ #[inline(always)]
+ fn into_query_param(self) -> DefId {
+ self.to_def_id()
+ }
+ }
}
use sealed::IntoQueryParam;
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 61c34730d..b25b4bd4f 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -5,8 +5,8 @@
//! subtyping, type equality, etc.
use crate::ty::error::{ExpectedFound, TypeError};
-use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
use crate::ty::{self, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{GenericArg, GenericArgKind, SubstsRef};
use rustc_hir as ast;
use rustc_hir::def_id::DefId;
use rustc_span::DUMMY_SP;
@@ -632,11 +632,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
// While this is slightly incorrect, it shouldn't matter for `min_const_generics`
// and is the better alternative to waiting until `generic_const_exprs` can
// be stabilized.
- (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
- if au.def == bu.def && au.promoted == bu.promoted =>
- {
- assert_eq!(au.promoted, ());
-
+ (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => {
let substs = relation.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
@@ -644,11 +640,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
bu.substs,
)?;
return Ok(tcx.mk_const(ty::ConstS {
- kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
- def: au.def,
- substs,
- promoted: (),
- }),
+ kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def: au.def, substs }),
ty: a.ty(),
}));
}
diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
index e86dafae3..e79b79a25 100644
--- a/compiler/rustc_middle/src/ty/rvalue_scopes.rs
+++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
@@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
/// `RvalueScopes` is a mapping from sub-expressions to _extended_ lifetime as determined by
-/// rules laid out in `rustc_typeck::check::rvalue_scopes`.
+/// rules laid out in `rustc_hir_analysis::check::rvalue_scopes`.
#[derive(TyEncodable, TyDecodable, Clone, Debug, Default, Eq, PartialEq, HashStable)]
pub struct RvalueScopes {
map: FxHashMap<hir::ItemLocalId, Option<Scope>>,
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 84d6a8b97..2cad333e3 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -166,8 +166,8 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
}
- ty::PredicateKind::ConstEvaluatable(uv) => {
- write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs)
+ ty::PredicateKind::ConstEvaluatable(ct) => {
+ write!(f, "ConstEvaluatable({ct:?})")
}
ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
@@ -560,18 +560,6 @@ impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Box<[T]> {
}
}
-impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::EarlyBinder<T> {
- fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
- self.try_map_bound(|ty| ty.try_fold_with(folder))
- }
-}
-
-impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for ty::EarlyBinder<T> {
- fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
- self.as_ref().0.visit_with(visitor)
- }
-}
-
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> {
fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
folder.try_fold_binder(self)
@@ -844,45 +832,8 @@ impl<'tcx> TypeVisitable<'tcx> for InferConst<'tcx> {
}
}
-impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
- fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
- folder.try_fold_unevaluated(self)
- }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for ty::Unevaluated<'tcx> {
- fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
- visitor.visit_unevaluated(*self)
- }
-}
-
-impl<'tcx> TypeSuperFoldable<'tcx> for ty::Unevaluated<'tcx> {
- fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
- self,
- folder: &mut F,
- ) -> Result<Self, F::Error> {
- Ok(ty::Unevaluated {
- def: self.def,
- substs: self.substs.try_fold_with(folder)?,
- promoted: self.promoted,
- })
- }
-}
-
-impl<'tcx> TypeSuperVisitable<'tcx> for ty::Unevaluated<'tcx> {
+impl<'tcx> TypeSuperVisitable<'tcx> for ty::UnevaluatedConst<'tcx> {
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.substs.visit_with(visitor)
}
}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> {
- fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
- Ok(self.expand().try_fold_with(folder)?.shrink())
- }
-}
-
-impl<'tcx> TypeVisitable<'tcx> for ty::Unevaluated<'tcx, ()> {
- fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
- self.expand().visit_with(visitor)
- }
-}
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 36e560850..cf420bafe 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -3,7 +3,7 @@
#![allow(rustc::usage_of_ty_tykind)]
use crate::infer::canonical::Canonical;
-use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
+use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
use crate::ty::visit::ValidateBoundVars;
use crate::ty::InferTy::*;
use crate::ty::{
@@ -19,7 +19,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_index::vec::Idx;
use rustc_macros::HashStable;
-use rustc_span::symbol::{kw, Symbol};
+use rustc_span::symbol::{kw, sym, Symbol};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi;
use std::borrow::Cow;
@@ -85,6 +85,17 @@ impl BoundRegionKind {
_ => false,
}
}
+
+ pub fn get_name(&self) -> Option<Symbol> {
+ if self.is_named() {
+ match *self {
+ BoundRegionKind::BrNamed(_, name) => return Some(name),
+ _ => unreachable!(),
+ }
+ }
+
+ None
+ }
}
pub trait Article {
@@ -304,7 +315,7 @@ impl<'tcx> ClosureSubsts<'tcx> {
/// closure.
// FIXME(eddyb) this should be unnecessary, as the shallowly resolved
// type is known at the time of the creation of `ClosureSubsts`,
- // see `rustc_typeck::check::closure`.
+ // see `rustc_hir_analysis::check::closure`.
pub fn sig_as_fn_ptr_ty(self) -> Ty<'tcx> {
self.split().closure_sig_as_fn_ptr_ty.expect_ty()
}
@@ -551,7 +562,7 @@ impl<'tcx> GeneratorSubsts<'tcx> {
layout.variant_fields.iter().map(move |variant| {
variant
.iter()
- .map(move |field| EarlyBinder(layout.field_tys[*field]).subst(tcx, self.substs))
+ .map(move |field| ty::EarlyBinder(layout.field_tys[*field]).subst(tcx, self.substs))
})
}
@@ -915,73 +926,6 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> {
}
}
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[derive(Encodable, Decodable, HashStable)]
-pub struct EarlyBinder<T>(pub T);
-
-impl<T> EarlyBinder<T> {
- pub fn as_ref(&self) -> EarlyBinder<&T> {
- EarlyBinder(&self.0)
- }
-
- pub fn map_bound_ref<F, U>(&self, f: F) -> EarlyBinder<U>
- where
- F: FnOnce(&T) -> U,
- {
- self.as_ref().map_bound(f)
- }
-
- pub fn map_bound<F, U>(self, f: F) -> EarlyBinder<U>
- where
- F: FnOnce(T) -> U,
- {
- let value = f(self.0);
- EarlyBinder(value)
- }
-
- pub fn try_map_bound<F, U, E>(self, f: F) -> Result<EarlyBinder<U>, E>
- where
- F: FnOnce(T) -> Result<U, E>,
- {
- let value = f(self.0)?;
- Ok(EarlyBinder(value))
- }
-
- pub fn rebind<U>(&self, value: U) -> EarlyBinder<U> {
- EarlyBinder(value)
- }
-}
-
-impl<T> EarlyBinder<Option<T>> {
- pub fn transpose(self) -> Option<EarlyBinder<T>> {
- self.0.map(|v| EarlyBinder(v))
- }
-}
-
-impl<T, U> EarlyBinder<(T, U)> {
- pub fn transpose_tuple2(self) -> (EarlyBinder<T>, EarlyBinder<U>) {
- (EarlyBinder(self.0.0), EarlyBinder(self.0.1))
- }
-}
-
-pub struct EarlyBinderIter<T> {
- t: T,
-}
-
-impl<T: IntoIterator> EarlyBinder<T> {
- pub fn transpose_iter(self) -> EarlyBinderIter<T::IntoIter> {
- EarlyBinderIter { t: self.0.into_iter() }
- }
-}
-
-impl<T: Iterator> Iterator for EarlyBinderIter<T> {
- type Item = EarlyBinder<T::Item>;
-
- fn next(&mut self) -> Option<Self::Item> {
- self.t.next().map(|i| EarlyBinder(i))
- }
-}
-
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
#[derive(HashStable)]
pub enum BoundVariableKind {
@@ -1200,9 +1144,13 @@ pub struct ProjectionTy<'tcx> {
impl<'tcx> ProjectionTy<'tcx> {
pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
- let parent = tcx.parent(self.item_def_id);
- assert_eq!(tcx.def_kind(parent), DefKind::Trait);
- parent
+ match tcx.def_kind(self.item_def_id) {
+ DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.item_def_id),
+ DefKind::ImplTraitPlaceholder => {
+ tcx.parent(tcx.impl_trait_in_trait_parent(self.item_def_id))
+ }
+ kind => bug!("unexpected DefKind in ProjectionTy: {kind:?}"),
+ }
}
/// Extracts the underlying trait reference and own substs from this projection.
@@ -1213,6 +1161,7 @@ impl<'tcx> ProjectionTy<'tcx> {
tcx: TyCtxt<'tcx>,
) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
let def_id = tcx.parent(self.item_def_id);
+ assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
let trait_generics = tcx.generics_of(def_id);
(
ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) },
@@ -1508,6 +1457,23 @@ impl<'tcx> Region<'tcx> {
*self.0.0
}
+ pub fn get_name(self) -> Option<Symbol> {
+ if self.has_name() {
+ let name = match *self {
+ ty::ReEarlyBound(ebr) => Some(ebr.name),
+ ty::ReLateBound(_, br) => br.kind.get_name(),
+ ty::ReFree(fr) => fr.bound_region.get_name(),
+ ty::ReStatic => Some(kw::StaticLifetime),
+ ty::RePlaceholder(placeholder) => placeholder.name.get_name(),
+ _ => None,
+ };
+
+ return name;
+ }
+
+ None
+ }
+
/// Is this region named by the user?
pub fn has_name(self) -> bool {
match *self {
@@ -2156,7 +2122,7 @@ impl<'tcx> Ty<'tcx> {
///
/// Note that during type checking, we use an inference variable
/// to represent the closure kind, because it has not yet been
- /// inferred. Once upvar inference (in `rustc_typeck/src/check/upvar.rs`)
+ /// inferred. Once upvar inference (in `rustc_hir_analysis/src/check/upvar.rs`)
/// is complete, that type variable will be unified.
pub fn to_opt_closure_kind(self) -> Option<ty::ClosureKind> {
match self.kind() {
@@ -2239,7 +2205,10 @@ impl<'tcx> Ty<'tcx> {
// These aren't even `Clone`
ty::Str | ty::Slice(..) | ty::Foreign(..) | ty::Dynamic(..) => false,
- ty::Int(..) | ty::Uint(..) | ty::Float(..) => true,
+ ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_))
+ | ty::Int(..)
+ | ty::Uint(..)
+ | ty::Float(..) => true,
// The voldemort ZSTs are fine.
ty::FnDef(..) => true,
@@ -2274,6 +2243,35 @@ impl<'tcx> Ty<'tcx> {
}
}
}
+
+ // If `self` is a primitive, return its [`Symbol`].
+ pub fn primitive_symbol(self) -> Option<Symbol> {
+ match self.kind() {
+ ty::Bool => Some(sym::bool),
+ ty::Char => Some(sym::char),
+ ty::Float(f) => match f {
+ ty::FloatTy::F32 => Some(sym::f32),
+ ty::FloatTy::F64 => Some(sym::f64),
+ },
+ ty::Int(f) => match f {
+ ty::IntTy::Isize => Some(sym::isize),
+ ty::IntTy::I8 => Some(sym::i8),
+ ty::IntTy::I16 => Some(sym::i16),
+ ty::IntTy::I32 => Some(sym::i32),
+ ty::IntTy::I64 => Some(sym::i64),
+ ty::IntTy::I128 => Some(sym::i128),
+ },
+ ty::Uint(f) => match f {
+ ty::UintTy::Usize => Some(sym::usize),
+ ty::UintTy::U8 => Some(sym::u8),
+ ty::UintTy::U16 => Some(sym::u16),
+ ty::UintTy::U32 => Some(sym::u32),
+ ty::UintTy::U64 => Some(sym::u64),
+ ty::UintTy::U128 => Some(sym::u128),
+ },
+ _ => None,
+ }
+ }
}
/// 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 8e69bf067..0660e9b79 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -1,12 +1,12 @@
// Type substitutions.
-use crate::mir;
use crate::ty::codec::{TyDecoder, TyEncoder};
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
use crate::ty::visit::{TypeVisitable, TypeVisitor};
use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
+use rustc_data_structures::captures::Captures;
use rustc_data_structures::intern::{Interned, WithStableHash};
use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
@@ -189,6 +189,14 @@ impl<'tcx> GenericArg<'tcx> {
_ => bug!("expected a const, but found another kind"),
}
}
+
+ pub fn is_non_region_infer(self) -> bool {
+ match self.unpack() {
+ GenericArgKind::Lifetime(_) => false,
+ GenericArgKind::Type(ty) => ty.is_ty_infer(),
+ GenericArgKind::Const(ct) => ct.is_ct_infer(),
+ }
+ }
}
impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> {
@@ -492,23 +500,107 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
}
impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &'tcx ty::List<T> {
+ #[inline]
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.iter().try_for_each(|t| t.visit_with(visitor))
}
}
-// Just call `foo.subst(tcx, substs)` to perform a substitution across `foo`.
-#[rustc_on_unimplemented(message = "Calling `subst` must now be done through an `EarlyBinder`")]
-pub trait Subst<'tcx>: Sized {
- type Inner;
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Encodable, Decodable, HashStable)]
+pub struct EarlyBinder<T>(pub T);
+
+/// For early binders, you should first call `subst` before using any visitors.
+impl<'tcx, T> !TypeFoldable<'tcx> for ty::EarlyBinder<T> {}
+impl<'tcx, T> !TypeVisitable<'tcx> for ty::EarlyBinder<T> {}
+
+impl<T> EarlyBinder<T> {
+ pub fn as_ref(&self) -> EarlyBinder<&T> {
+ EarlyBinder(&self.0)
+ }
- fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self::Inner;
+ pub fn map_bound_ref<F, U>(&self, f: F) -> EarlyBinder<U>
+ where
+ F: FnOnce(&T) -> U,
+ {
+ self.as_ref().map_bound(f)
+ }
+
+ pub fn map_bound<F, U>(self, f: F) -> EarlyBinder<U>
+ where
+ F: FnOnce(T) -> U,
+ {
+ let value = f(self.0);
+ EarlyBinder(value)
+ }
+
+ pub fn try_map_bound<F, U, E>(self, f: F) -> Result<EarlyBinder<U>, E>
+ where
+ F: FnOnce(T) -> Result<U, E>,
+ {
+ let value = f(self.0)?;
+ Ok(EarlyBinder(value))
+ }
+
+ pub fn rebind<U>(&self, value: U) -> EarlyBinder<U> {
+ EarlyBinder(value)
+ }
}
-impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for ty::EarlyBinder<T> {
- type Inner = T;
+impl<T> EarlyBinder<Option<T>> {
+ pub fn transpose(self) -> Option<EarlyBinder<T>> {
+ self.0.map(|v| EarlyBinder(v))
+ }
+}
+
+impl<T, U> EarlyBinder<(T, U)> {
+ pub fn transpose_tuple2(self) -> (EarlyBinder<T>, EarlyBinder<U>) {
+ (EarlyBinder(self.0.0), EarlyBinder(self.0.1))
+ }
+}
- fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self::Inner {
+impl<'tcx, 's, T: IntoIterator<Item = I>, I: TypeFoldable<'tcx>> EarlyBinder<T> {
+ pub fn subst_iter(
+ self,
+ tcx: TyCtxt<'tcx>,
+ substs: &'s [GenericArg<'tcx>],
+ ) -> impl Iterator<Item = I> + Captures<'s> + Captures<'tcx> {
+ self.0.into_iter().map(move |t| EarlyBinder(t).subst(tcx, substs))
+ }
+}
+
+impl<'tcx, 's, 'a, T: IntoIterator<Item = &'a I>, I: Copy + TypeFoldable<'tcx> + 'a>
+ EarlyBinder<T>
+{
+ pub fn subst_iter_copied(
+ self,
+ tcx: TyCtxt<'tcx>,
+ substs: &'s [GenericArg<'tcx>],
+ ) -> impl Iterator<Item = I> + Captures<'s> + Captures<'tcx> + Captures<'a> {
+ self.0.into_iter().map(move |t| EarlyBinder(*t).subst(tcx, substs))
+ }
+}
+
+pub struct EarlyBinderIter<T> {
+ t: T,
+}
+
+impl<T: IntoIterator> EarlyBinder<T> {
+ pub fn transpose_iter(self) -> EarlyBinderIter<T::IntoIter> {
+ EarlyBinderIter { t: self.0.into_iter() }
+ }
+}
+
+impl<T: Iterator> Iterator for EarlyBinderIter<T> {
+ type Item = EarlyBinder<T::Item>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.t.next().map(|i| EarlyBinder(i))
+ }
+}
+
+impl<'tcx, T: TypeFoldable<'tcx>> ty::EarlyBinder<T> {
+ pub fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> T {
let mut folder = SubstFolder { tcx, substs, binders_passed: 0 };
self.0.fold_with(&mut folder)
}
@@ -544,9 +636,21 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
#[cold]
#[inline(never)]
- fn region_param_out_of_range(data: ty::EarlyBoundRegion) -> ! {
+ fn region_param_out_of_range(data: ty::EarlyBoundRegion, substs: &[GenericArg<'_>]) -> ! {
bug!(
- "Region parameter out of range when substituting in region {} (index={})",
+ "Region parameter out of range when substituting in region {} (index={}, substs = {:?})",
+ data.name,
+ data.index,
+ substs,
+ )
+ }
+
+ #[cold]
+ #[inline(never)]
+ fn region_param_invalid(data: ty::EarlyBoundRegion, other: GenericArgKind<'_>) -> ! {
+ bug!(
+ "Unexpected parameter {:?} when substituting in region {} (index={})",
+ other,
data.name,
data.index
)
@@ -562,7 +666,8 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
let rk = self.substs.get(data.index as usize).map(|k| k.unpack());
match rk {
Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
- _ => region_param_out_of_range(data),
+ Some(other) => region_param_invalid(data, other),
+ None => region_param_out_of_range(data, self.substs),
}
}
_ => r,
@@ -587,11 +692,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
c.super_fold_with(self)
}
}
-
- #[inline]
- fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
- c.super_fold_with(self)
- }
}
impl<'a, 'tcx> SubstFolder<'a, 'tcx> {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 23ad4d27d..f72e236ed 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -2,12 +2,11 @@
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::ty::layout::IntegerExt;
-use crate::ty::query::TyCtxtAt;
-use crate::ty::subst::{GenericArgKind, Subst, SubstsRef};
use crate::ty::{
self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeVisitable,
};
+use crate::ty::{GenericArgKind, SubstsRef};
use rustc_apfloat::Float as _;
use rustc_ast as ast;
use rustc_attr::{self as attr, SignedInt, UnsignedInt};
@@ -821,12 +820,8 @@ impl<'tcx> Ty<'tcx> {
/// does copies even when the type actually doesn't satisfy the
/// full requirements for the `Copy` trait (cc #29149) -- this
/// winds up being reported as an error during NLL borrow check.
- pub fn is_copy_modulo_regions(
- self,
- tcx_at: TyCtxtAt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ) -> bool {
- self.is_trivially_pure_clone_copy() || tcx_at.is_copy_raw(param_env.and(self))
+ pub fn is_copy_modulo_regions(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+ self.is_trivially_pure_clone_copy() || tcx.is_copy_raw(param_env.and(self))
}
/// Checks whether values of this type `T` have a size known at
@@ -835,8 +830,8 @@ impl<'tcx> Ty<'tcx> {
/// over-approximation in generic contexts, where one can have
/// strange rules like `<T as Foo<'static>>::Bar: Sized` that
/// actually carry lifetime requirements.
- pub fn is_sized(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
- self.is_trivially_sized(tcx_at.tcx) || tcx_at.is_sized_raw(param_env.and(self))
+ pub fn is_sized(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+ self.is_trivially_sized(tcx) || tcx.is_sized_raw(param_env.and(self))
}
/// Checks whether values of this type `T` implement the `Freeze`
@@ -846,8 +841,8 @@ impl<'tcx> Ty<'tcx> {
/// optimization as well as the rules around static values. Note
/// that the `Freeze` trait is not exposed to end users and is
/// effectively an implementation detail.
- pub fn is_freeze(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
- self.is_trivially_freeze() || tcx_at.is_freeze_raw(param_env.and(self))
+ pub fn is_freeze(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+ self.is_trivially_freeze() || tcx.is_freeze_raw(param_env.and(self))
}
/// Fast path helper for testing if a type is `Freeze`.
@@ -886,8 +881,8 @@ impl<'tcx> Ty<'tcx> {
}
/// Checks whether values of this type `T` implement the `Unpin` trait.
- pub fn is_unpin(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
- self.is_trivially_unpin() || tcx_at.is_unpin_raw(param_env.and(self))
+ pub fn is_unpin(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+ self.is_trivially_unpin() || tcx.is_unpin_raw(param_env.and(self))
}
/// Fast path helper for testing if a type is `Unpin`.
@@ -958,7 +953,7 @@ impl<'tcx> Ty<'tcx> {
}
}
- /// Checks if `ty` has has a significant drop.
+ /// Checks if `ty` has a significant drop.
///
/// Note that this method can return false even if `ty` has a destructor
/// attached; even if that is the case then the adt has been marked with
@@ -1289,12 +1284,24 @@ pub fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
.any(|items| items.iter().any(|item| item.has_name(sym::hidden)))
}
+/// Determines whether an item is annotated with `doc(notable_trait)`.
+pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+ tcx.get_attrs(def_id, sym::doc)
+ .filter_map(|attr| attr.meta_item_list())
+ .any(|items| items.iter().any(|item| item.has_name(sym::notable_trait)))
+}
+
/// Determines whether an item is an intrinsic by Abi.
pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
matches!(tcx.fn_sig(def_id).abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic)
}
pub fn provide(providers: &mut ty::query::Providers) {
- *providers =
- ty::query::Providers { normalize_opaque_types, is_doc_hidden, is_intrinsic, ..*providers }
+ *providers = ty::query::Providers {
+ normalize_opaque_types,
+ is_doc_hidden,
+ is_doc_notable_trait,
+ is_intrinsic,
+ ..*providers
+ }
}
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 5f8cb5782..c09f71f9a 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -10,8 +10,7 @@
//!
//! There are three groups of traits involved in each traversal.
//! - `TypeVisitable`. This is implemented once for many types, including:
-//! - Types of interest, for which the the methods delegate to the
-//! visitor.
+//! - 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,
@@ -39,7 +38,6 @@
//! - ty.super_visit_with(visitor)
//! - u.visit_with(visitor)
//! ```
-use crate::mir;
use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
use rustc_errors::ErrorGuaranteed;
@@ -104,8 +102,8 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone {
None
}
}
- fn has_param_types_or_consts(&self) -> bool {
- self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM)
+ fn has_non_region_param(&self) -> bool {
+ self.has_type_flags(TypeFlags::NEEDS_SUBST - TypeFlags::HAS_RE_PARAM)
}
fn has_infer_regions(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_RE_INFER)
@@ -113,8 +111,8 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone {
fn has_infer_types(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_TY_INFER)
}
- fn has_infer_types_or_consts(&self) -> bool {
- self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_CT_INFER)
+ fn has_non_region_infer(&self) -> bool {
+ self.has_type_flags(TypeFlags::NEEDS_INFER - TypeFlags::HAS_RE_INFER)
}
fn needs_infer(&self) -> bool {
self.has_type_flags(TypeFlags::NEEDS_INFER)
@@ -199,17 +197,9 @@ pub trait TypeVisitor<'tcx>: Sized {
c.super_visit_with(self)
}
- fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
- uv.super_visit_with(self)
- }
-
fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
p.super_visit_with(self)
}
-
- fn visit_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> ControlFlow<Self::BreakTy> {
- c.super_visit_with(self)
- }
}
///////////////////////////////////////////////////////////////////////////
@@ -597,18 +587,6 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
#[inline]
#[instrument(level = "trace", ret)]
- fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
- let flags = FlagComputation::for_unevaluated_const(uv);
- trace!(r.flags=?flags);
- if flags.intersects(self.flags) {
- ControlFlow::Break(FoundFlags)
- } else {
- ControlFlow::CONTINUE
- }
- }
-
- #[inline]
- #[instrument(level = "trace", ret)]
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!(
"HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index a3e11bbf0..91db9698c 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -112,6 +112,22 @@ impl<'tcx> Ty<'tcx> {
}
}
+impl<'tcx> ty::Const<'tcx> {
+ /// Iterator that walks `self` and any types reachable from
+ /// `self`, in depth-first order. Note that just walks the types
+ /// that appear in `self`, it does not descend into the fields of
+ /// structs or variants. For example:
+ ///
+ /// ```text
+ /// isize => { isize }
+ /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
+ /// [isize] => { [isize], isize }
+ /// ```
+ pub fn walk(self) -> TypeWalker<'tcx> {
+ TypeWalker::new(self.into())
+ }
+}
+
/// We push `GenericArg`s on the stack in reverse order so as to
/// maintain a pre-order traversal. As of the time of this
/// writing, the fact that the traversal is pre-order is not
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index 7fbe9ae2a..f4b4c3fb0 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -1,8 +1,18 @@
-use rustc_middle::ty::{self, AdtSizedConstraint, Ty, TyCtxt};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_middle::ty::Representability;
+use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
+use rustc_query_system::query::QueryInfo;
use rustc_query_system::Value;
+use rustc_span::def_id::LocalDefId;
+use rustc_span::Span;
+
+use std::fmt::Write;
impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
- fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
+ fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
// SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
// FIXME: Represent the above fact in the trait system somehow.
unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.ty_error()) }
@@ -10,7 +20,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
}
impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> {
- fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
+ fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
// SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.
// FIXME: Represent the above fact in the trait system somehow.
unsafe {
@@ -21,20 +31,8 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> {
}
}
-impl<'tcx> Value<TyCtxt<'tcx>> for AdtSizedConstraint<'_> {
- fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
- // SAFETY: This is never called when `Self` is not `AdtSizedConstraint<'tcx>`.
- // FIXME: Represent the above fact in the trait system somehow.
- unsafe {
- std::mem::transmute::<AdtSizedConstraint<'tcx>, AdtSizedConstraint<'_>>(
- AdtSizedConstraint(tcx.intern_type_list(&[tcx.ty_error()])),
- )
- }
- }
-}
-
impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
- fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
+ fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo]) -> Self {
let err = tcx.ty_error();
// FIXME(compiler-errors): It would be nice if we could get the
// query key, so we could at least generate a fn signature that
@@ -52,3 +50,153 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
unsafe { std::mem::transmute::<ty::PolyFnSig<'tcx>, ty::Binder<'_, ty::FnSig<'_>>>(fn_sig) }
}
}
+
+impl<'tcx> Value<TyCtxt<'tcx>> for Representability {
+ fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo]) -> Self {
+ let mut item_and_field_ids = Vec::new();
+ let mut representable_ids = FxHashSet::default();
+ for info in cycle {
+ if info.query.name == "representability"
+ && let Some(field_id) = info.query.def_id
+ && let Some(field_id) = field_id.as_local()
+ && let Some(DefKind::Field) = info.query.def_kind
+ {
+ let parent_id = tcx.parent(field_id.to_def_id());
+ let item_id = match tcx.def_kind(parent_id) {
+ DefKind::Variant => tcx.parent(parent_id),
+ _ => parent_id,
+ };
+ item_and_field_ids.push((item_id.expect_local(), field_id));
+ }
+ }
+ for info in cycle {
+ if info.query.name == "representability_adt_ty"
+ && let Some(def_id) = info.query.ty_adt_id
+ && let Some(def_id) = def_id.as_local()
+ && !item_and_field_ids.iter().any(|&(id, _)| id == def_id)
+ {
+ representable_ids.insert(def_id);
+ }
+ }
+ recursive_type_error(tcx, item_and_field_ids, &representable_ids);
+ Representability::Infinite
+ }
+}
+
+// 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(
+ tcx: TyCtxt<'_>,
+ mut item_and_field_ids: Vec<(LocalDefId, LocalDefId)>,
+ representable_ids: &FxHashSet<LocalDefId>,
+) {
+ const ITEM_LIMIT: usize = 5;
+
+ // Rotate the cycle so that the item with the lowest span is first
+ let start_index = item_and_field_ids
+ .iter()
+ .enumerate()
+ .min_by_key(|&(_, &(id, _))| tcx.def_span(id))
+ .unwrap()
+ .0;
+ item_and_field_ids.rotate_left(start_index);
+
+ let cycle_len = item_and_field_ids.len();
+ let show_cycle_len = cycle_len.min(ITEM_LIMIT);
+
+ let mut err_span = MultiSpan::from_spans(
+ item_and_field_ids[..show_cycle_len]
+ .iter()
+ .map(|(id, _)| tcx.def_span(id.to_def_id()))
+ .collect(),
+ );
+ let mut suggestion = Vec::with_capacity(show_cycle_len * 2);
+ for i in 0..show_cycle_len {
+ let (_, field_id) = item_and_field_ids[i];
+ let (next_item_id, _) = item_and_field_ids[(i + 1) % cycle_len];
+ // Find the span(s) that contain the next item in the cycle
+ let hir_id = tcx.hir().local_def_id_to_hir_id(field_id);
+ let hir::Node::Field(field) = tcx.hir().get(hir_id) else { bug!("expected field") };
+ let mut found = Vec::new();
+ find_item_ty_spans(tcx, field.ty, next_item_id, &mut found, representable_ids);
+
+ // Couldn't find the type. Maybe it's behind a type alias?
+ // In any case, we'll just suggest boxing the whole field.
+ if found.is_empty() {
+ found.push(field.ty.span);
+ }
+
+ for span in found {
+ err_span.push_span_label(span, "recursive without indirection");
+ // FIXME(compiler-errors): This suggestion might be erroneous if Box is shadowed
+ suggestion.push((span.shrink_to_lo(), "Box<".to_string()));
+ suggestion.push((span.shrink_to_hi(), ">".to_string()));
+ }
+ }
+ 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());
+ write!(&mut s, "`{path}`").unwrap();
+ if i == (ITEM_LIMIT - 1) && cycle_len > ITEM_LIMIT {
+ write!(&mut s, " and {} more", cycle_len - 5).unwrap();
+ break;
+ }
+ if cycle_len > 1 && i < cycle_len - 2 {
+ s.push_str(", ");
+ } else if cycle_len > 1 && i == cycle_len - 2 {
+ s.push_str(" and ")
+ }
+ }
+ s
+ };
+ let mut err = struct_span_err!(
+ tcx.sess,
+ err_span,
+ E0072,
+ "recursive type{} {} {} infinite size",
+ pluralize!(cycle_len),
+ items_list,
+ pluralize!("has", cycle_len),
+ );
+ err.multipart_suggestion(
+ "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle",
+ suggestion,
+ Applicability::HasPlaceholders,
+ );
+ err.emit();
+}
+
+fn find_item_ty_spans(
+ tcx: TyCtxt<'_>,
+ ty: &hir::Ty<'_>,
+ needle: LocalDefId,
+ spans: &mut Vec<Span>,
+ seen_representable: &FxHashSet<LocalDefId>,
+) {
+ match ty.kind {
+ hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
+ if let Some(def_id) = path.res.opt_def_id() {
+ let check_params = def_id.as_local().map_or(true, |def_id| {
+ if def_id == needle {
+ spans.push(ty.span);
+ }
+ seen_representable.contains(&def_id)
+ });
+ if check_params && let Some(args) = path.segments.last().unwrap().args {
+ let params_in_repr = tcx.params_in_repr(def_id);
+ for (i, arg) in args.args.iter().enumerate() {
+ if let hir::GenericArg::Type(ty) = arg && params_in_repr.contains(i as u32) {
+ find_item_ty_spans(tcx, ty, needle, spans, seen_representable);
+ }
+ }
+ }
+ }
+ }
+ hir::TyKind::Array(ty, _) => find_item_ty_spans(tcx, ty, needle, spans, seen_representable),
+ hir::TyKind::Tup(tys) => {
+ tys.iter().for_each(|ty| find_item_ty_spans(tcx, ty, needle, spans, seen_representable))
+ }
+ _ => {}
+ }
+}
diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml
index 30f90e383..c726fa3a3 100644
--- a/compiler/rustc_mir_build/Cargo.toml
+++ b/compiler/rustc_mir_build/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
rustc_arena = { path = "../rustc_arena" }
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index 784583d94..183db56d7 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -221,26 +221,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let init = &this.thir[*initializer];
let initializer_span = init.span;
- this.declare_bindings(
- visibility_scope,
- remainder_span,
- pattern,
- ArmHasGuard(false),
- Some((None, initializer_span)),
- );
- this.visit_primary_bindings(
- pattern,
- UserTypeProjections::none(),
- &mut |this, _, _, _, node, span, _, _| {
- this.storage_live_binding(block, node, span, OutsideGuard, true);
- },
- );
let failure = unpack!(
block = this.in_opt_scope(
opt_destruction_scope.map(|de| (de, source_info)),
|this| {
let scope = (*init_scope, source_info);
this.in_scope(scope, *lint_level, |this| {
+ this.declare_bindings(
+ visibility_scope,
+ remainder_span,
+ pattern,
+ ArmHasGuard(false),
+ Some((None, initializer_span)),
+ );
+ this.visit_primary_bindings(
+ pattern,
+ UserTypeProjections::none(),
+ &mut |this, _, _, _, node, span, _, _| {
+ this.storage_live_binding(
+ block,
+ node,
+ span,
+ OutsideGuard,
+ true,
+ );
+ },
+ );
this.ast_let_else(
block,
init,
@@ -305,7 +311,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ArmHasGuard(false),
Some((None, initializer_span)),
);
- this.expr_into_pattern(block, &pattern, init) // irrefutable pattern
+ this.expr_into_pattern(block, &pattern, init)
+ // irrefutable pattern
})
},
)
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 c9bec130c..37dc1ad9f 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -2,6 +2,7 @@
use crate::build::{parse_float_into_constval, Builder};
use rustc_ast as ast;
+use rustc_middle::mir;
use rustc_middle::mir::interpret::{
Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
};
@@ -66,7 +67,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
})
});
- let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs);
+ let uneval =
+ mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
let literal = ConstantKind::Unevaluated(uneval, ty);
Constant { user_ty, span, literal }
@@ -79,7 +81,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Constant { user_ty: None, span, literal }
}
ExprKind::ConstBlock { did: def_id, substs } => {
- let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs);
+ let uneval =
+ mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
let literal = ConstantKind::Unevaluated(uneval, ty);
Constant { user_ty: None, span, literal }
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 e707c373f..c8610af70 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -153,12 +153,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if tcx.features().unsized_fn_params {
let ty = expr.ty;
- let span = expr.span;
let param_env = this.param_env;
- if !ty.is_sized(tcx.at(span), param_env) {
+ if !ty.is_sized(tcx, param_env) {
// !sized means !copy, so this is an unsized move
- assert!(!ty.is_copy_modulo_regions(tcx.at(span), param_env));
+ assert!(!ty.is_copy_modulo_regions(tcx, param_env));
// As described above, detect the case where we are passing a value of unsized
// type, and that value is coming from the deref of a box.
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 ebb56e5a2..396782d45 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -17,6 +17,7 @@ use rustc_target::abi::VariantIdx;
use rustc_index::vec::Idx;
+use std::assert_matches::assert_matches;
use std::iter;
/// The "outermost" place that holds this value.
@@ -69,7 +70,7 @@ pub(crate) enum PlaceBase {
/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
#[derive(Clone, Debug, PartialEq)]
-pub(crate) struct PlaceBuilder<'tcx> {
+pub(in crate::build) struct PlaceBuilder<'tcx> {
base: PlaceBase,
projection: Vec<PlaceElem<'tcx>>,
}
@@ -102,6 +103,8 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
variant = Some(*idx);
continue;
}
+ // These do not affect anything, they just make sure we know the right type.
+ ProjectionElem::OpaqueCast(_) => continue,
ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {
@@ -168,22 +171,22 @@ fn find_capture_matching_projections<'a, 'tcx>(
/// `PlaceBuilder` now starts from `PlaceBase::Local`.
///
/// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found.
-fn to_upvars_resolved_place_builder<'a, 'tcx>(
+#[instrument(level = "trace", skip(cx), ret)]
+fn to_upvars_resolved_place_builder<'tcx>(
from_builder: PlaceBuilder<'tcx>,
- tcx: TyCtxt<'tcx>,
- upvars: &'a CaptureMap<'tcx>,
+ cx: &Builder<'_, 'tcx>,
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
match from_builder.base {
PlaceBase::Local(_) => Ok(from_builder),
PlaceBase::Upvar { var_hir_id, closure_def_id } => {
let Some((capture_index, capture)) =
find_capture_matching_projections(
- upvars,
+ &cx.upvars,
var_hir_id,
&from_builder.projection,
) else {
- let closure_span = tcx.def_span(closure_def_id);
- if !enable_precise_capture(tcx, closure_span) {
+ let closure_span = cx.tcx.def_span(closure_def_id);
+ if !enable_precise_capture(cx.tcx, closure_span) {
bug!(
"No associated capture found for {:?}[{:#?}] even though \
capture_disjoint_fields isn't enabled",
@@ -200,12 +203,13 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
};
// Access the capture by accessing the field within the Closure struct.
- let capture_info = &upvars[capture_index];
+ let capture_info = &cx.upvars[capture_index];
let mut upvar_resolved_place_builder = PlaceBuilder::from(capture_info.use_place);
// We used some of the projections to build the capture itself,
// now we apply the remaining to the upvar resolved place.
+ trace!(?capture.captured_place, ?from_builder.projection);
let remaining_projections = strip_prefix(
capture.captured_place.place.base_ty,
from_builder.projection,
@@ -229,17 +233,20 @@ fn strip_prefix<'tcx>(
projections: Vec<PlaceElem<'tcx>>,
prefix_projections: &[HirProjection<'tcx>],
) -> impl Iterator<Item = PlaceElem<'tcx>> {
- let mut iter = projections.into_iter();
+ let mut iter = projections
+ .into_iter()
+ // Filter out opaque casts, they are unnecessary in the prefix.
+ .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(..)));
for projection in prefix_projections {
match projection.kind {
HirProjectionKind::Deref => {
- assert!(matches!(iter.next(), Some(ProjectionElem::Deref)));
+ assert_matches!(iter.next(), Some(ProjectionElem::Deref));
}
HirProjectionKind::Field(..) => {
if base_ty.is_enum() {
- assert!(matches!(iter.next(), Some(ProjectionElem::Downcast(..))));
+ assert_matches!(iter.next(), Some(ProjectionElem::Downcast(..)));
}
- assert!(matches!(iter.next(), Some(ProjectionElem::Field(..))));
+ assert_matches!(iter.next(), Some(ProjectionElem::Field(..)));
}
HirProjectionKind::Index | HirProjectionKind::Subslice => {
bug!("unexpected projection kind: {:?}", projection);
@@ -251,24 +258,16 @@ fn strip_prefix<'tcx>(
}
impl<'tcx> PlaceBuilder<'tcx> {
- pub(in crate::build) fn into_place<'a>(
- self,
- tcx: TyCtxt<'tcx>,
- upvars: &'a CaptureMap<'tcx>,
- ) -> Place<'tcx> {
+ pub(in crate::build) fn into_place(self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> {
if let PlaceBase::Local(local) = self.base {
- Place { local, projection: tcx.intern_place_elems(&self.projection) }
+ Place { local, projection: cx.tcx.intern_place_elems(&self.projection) }
} else {
- self.expect_upvars_resolved(tcx, upvars).into_place(tcx, upvars)
+ self.expect_upvars_resolved(cx).into_place(cx)
}
}
- fn expect_upvars_resolved<'a>(
- self,
- tcx: TyCtxt<'tcx>,
- upvars: &'a CaptureMap<'tcx>,
- ) -> PlaceBuilder<'tcx> {
- to_upvars_resolved_place_builder(self, tcx, upvars).unwrap()
+ fn expect_upvars_resolved(self, cx: &Builder<'_, 'tcx>) -> PlaceBuilder<'tcx> {
+ to_upvars_resolved_place_builder(self, cx).unwrap()
}
/// Attempts to resolve the `PlaceBuilder`.
@@ -282,18 +281,21 @@ impl<'tcx> PlaceBuilder<'tcx> {
/// not captured. This can happen because the final mir that will be
/// generated doesn't require a read for this place. Failures will only
/// happen inside closures.
- pub(in crate::build) fn try_upvars_resolved<'a>(
+ pub(in crate::build) fn try_upvars_resolved(
self,
- tcx: TyCtxt<'tcx>,
- upvars: &'a CaptureMap<'tcx>,
+ cx: &Builder<'_, 'tcx>,
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
- to_upvars_resolved_place_builder(self, tcx, upvars)
+ to_upvars_resolved_place_builder(self, cx)
}
pub(crate) fn base(&self) -> PlaceBase {
self.base
}
+ pub(crate) fn projection(&self) -> &[PlaceElem<'tcx>] {
+ &self.projection
+ }
+
pub(crate) fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
self.project(PlaceElem::Field(f, ty))
}
@@ -353,7 +355,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
expr: &Expr<'tcx>,
) -> BlockAnd<Place<'tcx>> {
let place_builder = unpack!(block = self.as_place_builder(block, expr));
- block.and(place_builder.into_place(self.tcx, &self.upvars))
+ block.and(place_builder.into_place(self))
}
/// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -377,7 +379,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
expr: &Expr<'tcx>,
) -> BlockAnd<Place<'tcx>> {
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
- block.and(place_builder.into_place(self.tcx, &self.upvars))
+ block.and(place_builder.into_place(self))
}
/// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -472,7 +474,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
inferred_ty: expr.ty,
});
- let place = place_builder.clone().into_place(this.tcx, &this.upvars);
+ let place = place_builder.clone().into_place(this);
this.cfg.push(
block,
Statement {
@@ -610,7 +612,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if is_outermost_index {
self.read_fake_borrows(block, fake_borrow_temps, source_info)
} else {
- base_place = base_place.expect_upvars_resolved(self.tcx, &self.upvars);
+ base_place = base_place.expect_upvars_resolved(self);
self.add_fake_borrows_of_base(
&base_place,
block,
@@ -638,12 +640,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let lt = self.temp(bool_ty, expr_span);
// len = len(slice)
- self.cfg.push_assign(
- block,
- source_info,
- len,
- Rvalue::Len(slice.into_place(self.tcx, &self.upvars)),
- );
+ self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.into_place(self)));
// lt = idx < len
self.cfg.push_assign(
block,
@@ -723,6 +720,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
ProjectionElem::Field(..)
| ProjectionElem::Downcast(..)
+ | ProjectionElem::OpaqueCast(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => (),
}
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 f88ab63f0..3dafdcb78 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -12,7 +12,7 @@ use rustc_middle::mir::AssertKind;
use rustc_middle::mir::Place;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
-use rustc_middle::ty::cast::CastTy;
+use rustc_middle::ty::cast::{mir_cast_kind, CastTy};
use rustc_middle::ty::{self, Ty, UpvarSubsts};
use rustc_span::Span;
@@ -217,16 +217,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let from_ty = CastTy::from_ty(ty);
let cast_ty = CastTy::from_ty(expr.ty);
debug!("ExprKind::Cast from_ty={from_ty:?}, cast_ty={:?}/{cast_ty:?}", expr.ty,);
- let cast_kind = match (from_ty, cast_ty) {
- (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
- CastKind::PointerExposeAddress
- }
- (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => {
- CastKind::PointerFromExposedAddress
- }
- (_, Some(CastTy::DynStar)) => CastKind::DynStar,
- (_, _) => CastKind::Misc,
- };
+ let cast_kind = mir_cast_kind(ty, expr.ty);
block.and(Rvalue::Cast(cast_kind, source, expr.ty))
}
ExprKind::Pointer { cast, source } => {
@@ -329,10 +320,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let place_builder =
unpack!(block = this.as_place_builder(block, &this.thir[*thir_place]));
- if let Ok(place_builder_resolved) =
- place_builder.try_upvars_resolved(this.tcx, &this.upvars)
- {
- let mir_place = place_builder_resolved.into_place(this.tcx, &this.upvars);
+ if let Ok(place_builder_resolved) = place_builder.try_upvars_resolved(this) {
+ let mir_place = place_builder_resolved.into_place(this);
this.cfg.push_fake_read(
block,
this.source_info(this.tcx.hir().span(*hir_id)),
@@ -623,8 +612,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// by the parent itself. The mutability of the current capture
// is same as that of the capture in the parent closure.
PlaceBase::Upvar { .. } => {
- let enclosing_upvars_resolved =
- arg_place_builder.clone().into_place(this.tcx, &this.upvars);
+ let enclosing_upvars_resolved = arg_place_builder.clone().into_place(this);
match enclosing_upvars_resolved.as_ref() {
PlaceRef {
@@ -661,7 +649,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
};
- let arg_place = arg_place_builder.into_place(this.tcx, &this.upvars);
+ let arg_place = arg_place_builder.into_place(this);
this.cfg.push_assign(
block,
diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
index e5dafb820..0ca4e3745 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
@@ -23,6 +23,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr, mutability))
}
+ #[instrument(skip(self), level = "debug")]
fn as_temp_inner(
&mut self,
mut block: BasicBlock,
@@ -30,10 +31,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
expr: &Expr<'tcx>,
mutability: Mutability,
) -> BlockAnd<Local> {
- debug!(
- "as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})",
- block, temp_lifetime, expr, mutability
- );
let this = self;
let expr_span = expr.span;
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 224a1b80f..24ecd0a53 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -15,14 +15,13 @@ use std::iter;
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr`, storing the result into `destination`, which
/// is assumed to be uninitialized.
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn expr_into_dest(
&mut self,
destination: Place<'tcx>,
mut block: BasicBlock,
expr: &Expr<'tcx>,
) -> BlockAnd<()> {
- debug!("expr_into_dest(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
-
// since we frequently have to reference `self` from within a
// closure, where `self` would be shadowed, it's easier to
// just use the name `this` uniformly
@@ -366,7 +365,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
None => {
let place_builder = place_builder.clone();
this.consume_by_copy_or_move(
- place_builder.field(n, *ty).into_place(this.tcx, &this.upvars),
+ place_builder.field(n, *ty).into_place(this),
)
}
})
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 93f382cc6..3f813e0af 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -220,10 +220,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let cause_matched_place = FakeReadCause::ForMatchedPlace(None);
let source_info = self.source_info(scrutinee_span);
- if let Ok(scrutinee_builder) =
- scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, &self.upvars)
- {
- let scrutinee_place = scrutinee_builder.into_place(self.tcx, &self.upvars);
+ if let Ok(scrutinee_builder) = scrutinee_place_builder.clone().try_upvars_resolved(self) {
+ let scrutinee_place = scrutinee_builder.into_place(self);
self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place);
}
@@ -246,7 +244,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
.map(|arm| {
let arm = &self.thir[arm];
let arm_has_guard = arm.guard.is_some();
- let arm_candidate = Candidate::new(scrutinee.clone(), &arm.pattern, arm_has_guard);
+ let arm_candidate =
+ Candidate::new(scrutinee.clone(), &arm.pattern, arm_has_guard, self);
(arm, arm_candidate)
})
.collect()
@@ -349,9 +348,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None;
let scrutinee_place: Place<'tcx>;
if let Ok(scrutinee_builder) =
- scrutinee_place_builder.clone().try_upvars_resolved(this.tcx, &this.upvars)
+ scrutinee_place_builder.clone().try_upvars_resolved(this)
{
- scrutinee_place = scrutinee_builder.into_place(this.tcx, &this.upvars);
+ scrutinee_place = scrutinee_builder.into_place(this);
opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span));
}
let scope = this.declare_bindings(
@@ -584,7 +583,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
initializer: PlaceBuilder<'tcx>,
set_match_place: bool,
) -> BlockAnd<()> {
- let mut candidate = Candidate::new(initializer.clone(), &irrefutable_pat, false);
+ let mut candidate = Candidate::new(initializer.clone(), &irrefutable_pat, false, self);
let fake_borrow_temps = self.lower_match_tree(
block,
irrefutable_pat.span,
@@ -601,12 +600,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
while let Some(next) = {
for binding in &candidate_ref.bindings {
let local = self.var_local_id(binding.var_id, OutsideGuard);
-
- let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
- VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
- )))) = self.local_decls[local].local_info else {
- bug!("Let binding to non-user variable.")
- };
// `try_upvars_resolved` may fail if it is unable to resolve the given
// `PlaceBuilder` inside a closure. In this case, we don't want to include
// a scrutinee place. `scrutinee_place_builder` will fail for destructured
@@ -621,10 +614,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// let (v1, v2) = foo;
// };
// ```
- if let Ok(match_pair_resolved) =
- initializer.clone().try_upvars_resolved(self.tcx, &self.upvars)
- {
- let place = match_pair_resolved.into_place(self.tcx, &self.upvars);
+ if let Ok(match_pair_resolved) = initializer.clone().try_upvars_resolved(self) {
+ let place = match_pair_resolved.into_place(self);
+
+ let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+ VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
+ )))) = self.local_decls[local].local_info else {
+ bug!("Let binding to non-user variable.")
+ };
*match_place = Some(place);
}
}
@@ -654,6 +651,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// scope for the bindings in these patterns, if such a scope had to be
/// created. NOTE: Declaring the bindings should always be done in their
/// drop scope.
+ #[instrument(skip(self), level = "debug")]
pub(crate) fn declare_bindings(
&mut self,
mut visibility_scope: Option<SourceScope>,
@@ -662,7 +660,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
has_guard: ArmHasGuard,
opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,
) -> Option<SourceScope> {
- debug!("declare_bindings: pattern={:?}", pattern);
self.visit_primary_bindings(
&pattern,
UserTypeProjections::none(),
@@ -868,11 +865,16 @@ struct Candidate<'pat, 'tcx> {
}
impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
- fn new(place: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, has_guard: bool) -> Self {
+ fn new(
+ place: PlaceBuilder<'tcx>,
+ pattern: &'pat Pat<'tcx>,
+ has_guard: bool,
+ cx: &Builder<'_, 'tcx>,
+ ) -> Self {
Candidate {
span: pattern.span,
has_guard,
- match_pairs: smallvec![MatchPair { place, pattern }],
+ match_pairs: smallvec![MatchPair::new(place, pattern, cx)],
bindings: Vec::new(),
ascriptions: Vec::new(),
subcandidates: Vec::new(),
@@ -1048,6 +1050,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// if `x.0` matches `false` (for the third arm). In the (impossible at
/// runtime) case when `x.0` is now `true`, we branch to
/// `otherwise_block`.
+ #[instrument(skip(self, fake_borrows), level = "debug")]
fn match_candidates<'pat>(
&mut self,
span: Span,
@@ -1057,11 +1060,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidates: &mut [&mut Candidate<'pat, 'tcx>],
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
) {
- debug!(
- "matched_candidate(span={:?}, candidates={:?}, start_block={:?}, otherwise_block={:?})",
- span, candidates, start_block, otherwise_block,
- );
-
// Start by simplifying candidates. Once this process is complete, all
// the match pairs which remain require some form of test, whether it
// be a switch or pattern comparison.
@@ -1380,6 +1378,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
)
}
+ #[instrument(
+ skip(self, otherwise, or_span, place, fake_borrows, candidate, pats),
+ level = "debug"
+ )]
fn test_or_pattern<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
@@ -1389,10 +1391,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place: PlaceBuilder<'tcx>,
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
) {
- debug!("test_or_pattern:\ncandidate={:#?}\npats={:#?}", candidate, pats);
+ debug!("candidate={:#?}\npats={:#?}", candidate, pats);
let mut or_candidates: Vec<_> = pats
.iter()
- .map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard))
+ .map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard, self))
.collect();
let mut or_candidate_refs: Vec<_> = or_candidates.iter_mut().collect();
let otherwise = if candidate.otherwise_block.is_some() {
@@ -1605,9 +1607,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Insert a Shallow borrow of any places that is switched on.
if let Some(fb) = fake_borrows && let Ok(match_place_resolved) =
- match_place.clone().try_upvars_resolved(self.tcx, &self.upvars)
+ match_place.clone().try_upvars_resolved(self)
{
- let resolved_place = match_place_resolved.into_place(self.tcx, &self.upvars);
+ let resolved_place = match_place_resolved.into_place(self);
fb.insert(resolved_place);
}
@@ -1634,9 +1636,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidates = rest;
}
// at least the first candidate ought to be tested
- assert!(total_candidate_count > candidates.len());
- debug!("test_candidates: tested_candidates: {}", total_candidate_count - candidates.len());
- debug!("test_candidates: untested_candidates: {}", candidates.len());
+ assert!(
+ total_candidate_count > candidates.len(),
+ "{}, {:#?}",
+ total_candidate_count,
+ candidates
+ );
+ debug!("tested_candidates: {}", total_candidate_count - candidates.len());
+ debug!("untested_candidates: {}", candidates.len());
// HACK(matthewjasper) This is a closure so that we can let the test
// create its blocks before the rest of the match. This currently
@@ -1783,8 +1790,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let expr_span = expr.span;
let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr, expr_span));
let wildcard = Pat::wildcard_from_ty(pat.ty);
- let mut guard_candidate = Candidate::new(expr_place_builder.clone(), &pat, false);
- let mut otherwise_candidate = Candidate::new(expr_place_builder.clone(), &wildcard, false);
+ let mut guard_candidate = Candidate::new(expr_place_builder.clone(), &pat, false, self);
+ let mut otherwise_candidate =
+ Candidate::new(expr_place_builder.clone(), &wildcard, false, self);
let fake_borrow_temps = self.lower_match_tree(
block,
pat.span,
@@ -1794,8 +1802,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
let mut opt_expr_place: Option<(Option<&Place<'tcx>>, Span)> = None;
let expr_place: Place<'tcx>;
- if let Ok(expr_builder) = expr_place_builder.try_upvars_resolved(self.tcx, &self.upvars) {
- expr_place = expr_builder.into_place(self.tcx, &self.upvars);
+ if let Ok(expr_builder) = expr_place_builder.try_upvars_resolved(self) {
+ expr_place = expr_builder.into_place(self);
opt_expr_place = Some((Some(&expr_place), expr_span));
}
let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();
@@ -2209,6 +2217,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// first local is a binding for occurrences of `var` in the guard, which
/// will have type `&T`. The second local is a binding for occurrences of
/// `var` in the arm body, which will have type `T`.
+ #[instrument(skip(self), level = "debug")]
fn declare_binding(
&mut self,
source_info: SourceInfo,
@@ -2223,19 +2232,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
pat_span: Span,
) {
- debug!(
- "declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \
- visibility_scope={:?}, source_info={:?})",
- var_id, name, mode, var_ty, visibility_scope, source_info
- );
-
let tcx = self.tcx;
let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope };
let binding_mode = match mode {
BindingMode::ByValue => ty::BindingMode::BindByValue(mutability),
BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability),
};
- debug!("declare_binding: user_ty={:?}", user_ty);
let local = LocalDecl::<'tcx> {
mutability,
ty: var_ty,
@@ -2285,7 +2287,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} else {
LocalsForNode::One(for_arm_body)
};
- debug!("declare_binding: vars={:?}", locals);
+ debug!(?locals);
self.var_indices.insert(var_id, locals);
}
@@ -2302,8 +2304,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let (matching, failure) = self.in_if_then_scope(*let_else_scope, else_block_span, |this| {
let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span));
let pat = Pat { ty: init.ty, span: else_block_span, kind: PatKind::Wild };
- let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false);
- let mut candidate = Candidate::new(scrutinee.clone(), pattern, false);
+ let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false, this);
+ let mut candidate = Candidate::new(scrutinee.clone(), pattern, false, this);
let fake_borrow_temps = this.lower_match_tree(
block,
initializer_span,
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index df221d356..924d2f555 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -37,12 +37,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
///
/// only generates a single switch. If this happens this method returns
/// `true`.
+ #[instrument(skip(self, candidate), level = "debug")]
pub(super) fn simplify_candidate<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
) -> bool {
// repeatedly simplify match pairs until fixed point is reached
- debug!(?candidate, "simplify_candidate");
+ debug!("{candidate:#?}");
// existing_bindings and new_bindings exists to keep the semantics in order.
// Reversing the binding order for bindings after `@` changes the binding order in places
@@ -131,7 +132,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
) -> Vec<Candidate<'pat, 'tcx>> {
pats.iter()
.map(|box pat| {
- let mut candidate = Candidate::new(place.clone(), pat, candidate.has_guard);
+ let mut candidate = Candidate::new(place.clone(), pat, candidate.has_guard, self);
self.simplify_candidate(&mut candidate);
candidate
})
@@ -155,17 +156,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ascription: thir::Ascription { ref annotation, variance },
} => {
// Apply the type ascription to the value at `match_pair.place`, which is the
- if let Ok(place_resolved) =
- match_pair.place.clone().try_upvars_resolved(self.tcx, &self.upvars)
- {
+ if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) {
candidate.ascriptions.push(Ascription {
annotation: annotation.clone(),
- source: place_resolved.into_place(self.tcx, &self.upvars),
+ source: place_resolved.into_place(self),
variance,
});
}
- candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
+ candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern, self));
Ok(())
}
@@ -184,12 +183,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ref subpattern,
is_primary: _,
} => {
- if let Ok(place_resolved) =
- match_pair.place.clone().try_upvars_resolved(self.tcx, &self.upvars)
- {
+ if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) {
candidate.bindings.push(Binding {
span: match_pair.pattern.span,
- source: place_resolved.into_place(self.tcx, &self.upvars),
+ source: place_resolved.into_place(self),
var_id: var,
binding_mode: mode,
});
@@ -197,7 +194,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if let Some(subpattern) = subpattern.as_ref() {
// this is the `x @ P` case; have to keep matching against `P` now
- candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
+ candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern, self));
}
Ok(())
@@ -267,14 +264,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
i == variant_index || {
self.tcx.features().exhaustive_patterns
- && !v
- .uninhabited_from(
- self.tcx,
- substs,
- adt_def.adt_kind(),
- self.param_env,
- )
- .is_empty()
+ && v.inhabited_predicate(self.tcx, adt_def)
+ .subst(self.tcx, substs)
+ .apply_any_module(self.tcx, self.param_env)
+ != Some(true)
}
}) && (adt_def.did().is_local()
|| !adt_def.is_variant_list_non_exhaustive());
@@ -308,7 +301,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
PatKind::Deref { ref subpattern } => {
let place_builder = match_pair.place.deref();
- candidate.match_pairs.push(MatchPair::new(place_builder, subpattern));
+ candidate.match_pairs.push(MatchPair::new(place_builder, subpattern, self));
Ok(())
}
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 47d05a6e3..b597ecfaa 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -14,8 +14,8 @@ use rustc_hir::{LangItem, RangeEnd};
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
-use rustc_middle::ty::subst::{GenericArg, Subst};
use rustc_middle::ty::util::IntTypeExt;
+use rustc_middle::ty::GenericArg;
use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
use rustc_span::def_id::DefId;
use rustc_span::symbol::{sym, Symbol};
@@ -144,6 +144,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
+ #[instrument(skip(self, make_target_blocks, place_builder), level = "debug")]
pub(super) fn perform_test(
&mut self,
match_start_span: Span,
@@ -153,19 +154,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
test: &Test<'tcx>,
make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
) {
- let place: Place<'tcx>;
- if let Ok(test_place_builder) = place_builder.try_upvars_resolved(self.tcx, &self.upvars) {
- place = test_place_builder.into_place(self.tcx, &self.upvars);
- } else {
- return;
- }
- debug!(
- "perform_test({:?}, {:?}: {:?}, {:?})",
- block,
- place,
- place.ty(&self.local_decls, self.tcx),
- test
- );
+ let place = place_builder.into_place(self);
+ let place_ty = place.ty(&self.local_decls, self.tcx);
+ debug!(?place, ?place_ty,);
let source_info = self.source_info(test.span);
match test.kind {
@@ -733,14 +724,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
// we want to create a set of derived match-patterns like
// `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
- let elem =
- ProjectionElem::Downcast(Some(adt_def.variant(variant_index).name), variant_index);
- let downcast_place = match_pair.place.project(elem); // `(x as Variant)`
+ let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)`
let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
// e.g., `(x as Variant).0`
let place = downcast_place.clone().field(subpattern.field, subpattern.pattern.ty);
// e.g., `(x as Variant).0 @ P1`
- MatchPair::new(place, &subpattern.pattern)
+ MatchPair::new(place, &subpattern.pattern, self)
});
candidate.match_pairs.extend(consequent_match_pairs);
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index b61c4fe50..b854ba47f 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -1,9 +1,11 @@
+use crate::build::expr::as_place::PlaceBase;
use crate::build::expr::as_place::PlaceBuilder;
use crate::build::matches::MatchPair;
use crate::build::Builder;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty;
+use rustc_middle::ty::TypeVisitable;
use smallvec::SmallVec;
use std::convert::TryInto;
@@ -17,7 +19,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
.iter()
.map(|fieldpat| {
let place = place.clone().field(fieldpat.field, fieldpat.pattern.ty);
- MatchPair::new(place, &fieldpat.pattern)
+ MatchPair::new(place, &fieldpat.pattern, self)
})
.collect()
}
@@ -31,23 +33,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
suffix: &'pat [Box<Pat<'tcx>>],
) {
let tcx = self.tcx;
- let (min_length, exact_size) = if let Ok(place_resolved) =
- place.clone().try_upvars_resolved(tcx, &self.upvars)
- {
- match place_resolved.into_place(tcx, &self.upvars).ty(&self.local_decls, tcx).ty.kind()
- {
- ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
- _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
- }
- } else {
- ((prefix.len() + suffix.len()).try_into().unwrap(), false)
- };
+ let (min_length, exact_size) =
+ if let Ok(place_resolved) = place.clone().try_upvars_resolved(self) {
+ match place_resolved.into_place(self).ty(&self.local_decls, tcx).ty.kind() {
+ ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
+ _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
+ }
+ } else {
+ ((prefix.len() + suffix.len()).try_into().unwrap(), false)
+ };
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
let elem =
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
let place = place.clone().project(elem);
- MatchPair::new(place, subpattern)
+ MatchPair::new(place, subpattern, self)
}));
if let Some(subslice_pat) = opt_slice {
@@ -57,7 +57,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
to: if exact_size { min_length - suffix_len } else { suffix_len },
from_end: !exact_size,
});
- match_pairs.push(MatchPair::new(subslice, subslice_pat));
+ match_pairs.push(MatchPair::new(subslice, subslice_pat, self));
}
match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| {
@@ -68,7 +68,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
from_end: !exact_size,
};
let place = place.clone().project(elem);
- MatchPair::new(place, subpattern)
+ MatchPair::new(place, subpattern, self)
}));
}
@@ -96,10 +96,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
- pub(crate) fn new(
+ pub(in crate::build) fn new(
place: PlaceBuilder<'tcx>,
pattern: &'pat Pat<'tcx>,
+ cx: &Builder<'_, 'tcx>,
) -> MatchPair<'pat, 'tcx> {
+ // Force the place type to the pattern's type.
+ // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
+ let mut place = match place.try_upvars_resolved(cx) {
+ Ok(val) | Err(val) => val,
+ };
+
+ // Only add the OpaqueCast projection if the given place is an opaque type and the
+ // expected type from the pattern is not.
+ let may_need_cast = match place.base() {
+ PlaceBase::Local(local) => {
+ let ty = Place::ty_from(local, place.projection(), &cx.local_decls, cx.tcx).ty;
+ ty != pattern.ty && ty.has_opaque_types()
+ }
+ _ => true,
+ };
+ if may_need_cast {
+ place = place.project(ProjectionElem::OpaqueCast(pattern.ty));
+ }
MatchPair { place, pattern }
}
}
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 25c4e51cb..cbcf9cd12 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -157,7 +157,7 @@ struct BlockContext(Vec<BlockFrame>);
struct Builder<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
- infcx: InferCtxt<'a, 'tcx>,
+ infcx: InferCtxt<'tcx>,
typeck_results: &'tcx TypeckResults<'tcx>,
region_scope_tree: &'tcx region::ScopeTree,
param_env: ty::ParamEnv<'tcx>,
@@ -481,54 +481,49 @@ fn construct_fn<'tcx>(
(None, fn_sig.output())
};
- let mut body = tcx.infer_ctxt().enter(|infcx| {
- let mut builder = Builder::new(
- thir,
- infcx,
- fn_def,
- fn_id,
- span_with_body,
- arguments.len(),
- safety,
- return_ty,
- return_ty_span,
- generator_kind,
- );
+ let infcx = tcx.infer_ctxt().build();
+ let mut builder = Builder::new(
+ thir,
+ infcx,
+ fn_def,
+ fn_id,
+ span_with_body,
+ arguments.len(),
+ safety,
+ return_ty,
+ return_ty_span,
+ generator_kind,
+ );
- let call_site_scope =
- region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::CallSite };
- let arg_scope =
- region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::Arguments };
- let source_info = builder.source_info(span);
- let call_site_s = (call_site_scope, source_info);
- unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| {
- let arg_scope_s = (arg_scope, source_info);
- // Attribute epilogue to function's closing brace
- let fn_end = span_with_body.shrink_to_hi();
- let return_block = unpack!(builder.in_breakable_scope(
- None,
- Place::return_place(),
- fn_end,
- |builder| {
- Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
- builder.args_and_body(
- START_BLOCK,
- fn_def.did,
- arguments,
- arg_scope,
- &thir[expr],
- )
- }))
- }
- ));
- let source_info = builder.source_info(fn_end);
- builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
- builder.build_drop_trees();
- return_block.unit()
- }));
-
- builder.finish()
- });
+ let call_site_scope =
+ region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::CallSite };
+ let arg_scope =
+ region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::Arguments };
+ let source_info = builder.source_info(span);
+ let call_site_s = (call_site_scope, source_info);
+ unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| {
+ let arg_scope_s = (arg_scope, source_info);
+ // Attribute epilogue to function's closing brace
+ let fn_end = span_with_body.shrink_to_hi();
+ let return_block =
+ unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| {
+ Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
+ builder.args_and_body(
+ START_BLOCK,
+ fn_def.did,
+ arguments,
+ arg_scope,
+ &thir[expr],
+ )
+ }))
+ }));
+ let source_info = builder.source_info(fn_end);
+ builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
+ builder.build_drop_trees();
+ return_block.unit()
+ }));
+
+ let mut body = builder.finish();
body.spread_arg = if abi == Abi::RustCall {
// RustCall pseudo-ABI untuples the last argument.
@@ -584,30 +579,29 @@ fn construct_const<'a, 'tcx>(
let typeck_results = tcx.typeck_opt_const_arg(def);
let const_ty = typeck_results.node_type(hir_id);
- tcx.infer_ctxt().enter(|infcx| {
- let mut builder = Builder::new(
- thir,
- infcx,
- def,
- hir_id,
- span,
- 0,
- Safety::Safe,
- const_ty,
- const_ty_span,
- None,
- );
+ let infcx = tcx.infer_ctxt().build();
+ let mut builder = Builder::new(
+ thir,
+ infcx,
+ def,
+ hir_id,
+ span,
+ 0,
+ Safety::Safe,
+ const_ty,
+ const_ty_span,
+ None,
+ );
- let mut block = START_BLOCK;
- unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr]));
+ let mut block = START_BLOCK;
+ unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr]));
- let source_info = builder.source_info(span);
- builder.cfg.terminate(block, source_info, TerminatorKind::Return);
+ let source_info = builder.source_info(span);
+ builder.cfg.terminate(block, source_info, TerminatorKind::Return);
- builder.build_drop_trees();
+ builder.build_drop_trees();
- builder.finish()
- })
+ builder.finish()
}
/// Construct MIR for an item that has had errors in type checking.
@@ -683,7 +677,7 @@ fn construct_error<'tcx>(
impl<'a, 'tcx> Builder<'a, 'tcx> {
fn new(
thir: &'a Thir<'tcx>,
- infcx: InferCtxt<'a, 'tcx>,
+ infcx: InferCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
hir_id: hir::HirId,
span: Span,
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index ff66ca595..3cebd5ebe 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -555,6 +555,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Convenience wrapper that pushes a scope and then executes `f`
/// to build its contents, popping the scope afterwards.
+ #[instrument(skip(self, f), level = "debug")]
pub(crate) fn in_scope<F, R>(
&mut self,
region_scope: (region::Scope, SourceInfo),
@@ -564,7 +565,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
where
F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>,
{
- debug!("in_scope(region_scope={:?})", region_scope);
let source_scope = self.source_scope;
let tcx = self.tcx;
if let LintLevel::Explicit(current_hir_id) = lint_level {
@@ -591,7 +591,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let rv = unpack!(block = f(self));
unpack!(block = self.pop_scope(region_scope, block));
self.source_scope = source_scope;
- debug!("in_scope: exiting region_scope={:?} block={:?}", region_scope, block);
+ debug!(?block);
block.and(rv)
}
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 495738ebe..fb1ea9ed3 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -89,15 +89,8 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
UNSAFE_OP_IN_UNSAFE_FN,
self.hir_context,
span,
- |lint| {
- lint.build(&format!(
- "{} is unsafe and requires unsafe block (error E0133)",
- description,
- ))
- .span_label(span, kind.simple_description())
- .note(note)
- .emit();
- },
+ format!("{} is unsafe and requires unsafe block (error E0133)", description,),
+ |lint| lint.span_label(span, kind.simple_description()).note(note),
)
}
SafetyContext::Safe => {
@@ -125,14 +118,13 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
enclosing_unsafe: Option<(Span, &'static str)>,
) {
let block_span = self.tcx.sess.source_map().guess_head_span(block_span);
- self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, |lint| {
- let msg = "unnecessary `unsafe` block";
- let mut db = lint.build(msg);
- db.span_label(block_span, msg);
+ let msg = "unnecessary `unsafe` block";
+ self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, msg, |lint| {
+ lint.span_label(block_span, msg);
if let Some((span, kind)) = enclosing_unsafe {
- db.span_label(span, format!("because it's nested under this `unsafe` {}", kind));
+ lint.span_label(span, format!("because it's nested under this `unsafe` {}", kind));
}
- db.emit();
+ lint
});
}
@@ -268,7 +260,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
};
match borrow_kind {
BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {
- if !ty.is_freeze(self.tcx.at(pat.span), self.param_env) {
+ if !ty.is_freeze(self.tcx, self.param_env) {
self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
}
}
@@ -364,7 +356,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
// If the called function has target features the calling function hasn't,
// the call requires `unsafe`. Don't check this on wasm
// targets, though. For more information on wasm see the
- // is_like_wasm check in typeck/src/collect.rs
+ // is_like_wasm check in hir_analysis/src/collect.rs
if !self.tcx.sess.target.options.is_like_wasm
&& !self
.tcx
@@ -465,9 +457,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
if visitor.found {
match borrow_kind {
BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique
- if !self.thir[arg]
- .ty
- .is_freeze(self.tcx.at(self.thir[arg].span), self.param_env) =>
+ if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) =>
{
self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField)
}
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 0c0a2fe9c..b53bd3d07 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -2,11 +2,11 @@
//!
//! This crate also contains the match exhaustiveness and usefulness checking.
#![allow(rustc::potential_query_instability)]
+#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
#![feature(if_let_guard)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(min_specialization)]
#![feature(once_cell)]
#![recursion_limit = "256"]
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index 54d549fd6..b21f30efc 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -36,16 +36,20 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let sp = tcx.def_span(def_id);
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- tcx.struct_span_lint_hir(UNCONDITIONAL_RECURSION, hir_id, sp, |lint| {
- let mut db = lint.build("function cannot return without recursing");
- db.span_label(sp, "cannot return without recursing");
- // offer some help to the programmer.
- for call_span in vis.reachable_recursive_calls {
- db.span_label(call_span, "recursive call site");
- }
- db.help("a `loop` may express intention better if this is on purpose");
- db.emit();
- });
+ tcx.struct_span_lint_hir(
+ UNCONDITIONAL_RECURSION,
+ hir_id,
+ sp,
+ "function cannot return without recursing",
+ |lint| {
+ lint.span_label(sp, "cannot return without recursing");
+ // offer some help to the programmer.
+ for call_span in vis.reachable_recursive_calls {
+ lint.span_label(call_span, "recursive call site");
+ }
+ lint.help("a `loop` may express intention better if this is on purpose")
+ },
+ );
}
}
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index d059877f8..c7a7c3e3f 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -48,6 +48,8 @@ impl<'tcx> Cx<'tcx> {
_ => None,
};
+ trace!(?expr.ty);
+
// Now apply adjustments, if any.
for adjustment in self.typeck_results.expr_adjustments(hir_expr) {
trace!(?expr, ?adjustment);
@@ -56,6 +58,8 @@ impl<'tcx> Cx<'tcx> {
self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span));
}
+ trace!(?expr.ty, "after adjustments");
+
// Next, wrap this up in the expr's scope.
expr = Expr {
temp_lifetime,
@@ -155,6 +159,7 @@ impl<'tcx> Cx<'tcx> {
Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
ExprKind::AddressOf { mutability, arg: self.thir.exprs.push(expr) }
}
+ Adjust::DynStar => ExprKind::Cast { source: self.thir.exprs.push(expr) },
};
Expr { temp_lifetime, ty: adjustment.target, span, kind }
@@ -994,7 +999,7 @@ impl<'tcx> Cx<'tcx> {
.temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
let var_ty = place.base_ty;
- // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path
+ // The result of capture analysis in `rustc_hir_analysis/check/upvar.rs`represents a captured path
// as it's seen for use within the closure and not at the time of closure creation.
//
// That is we see expect to see it start from a captured upvar and not something that is local
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 3ef1b263f..1d95d6b53 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -15,7 +15,7 @@ use rustc_hir::HirId;
use rustc_hir::Node;
use rustc_middle::middle::region;
use rustc_middle::thir::*;
-use rustc_middle::ty::{self, RvalueScopes, Subst, TyCtxt};
+use rustc_middle::ty::{self, RvalueScopes, TyCtxt};
use rustc_span::Span;
pub(crate) fn thir_body<'tcx>(
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 d45b88690..858129c74 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -7,7 +7,7 @@ use super::{PatCtxt, PatternError};
use rustc_arena::TypedArena;
use rustc_ast::Mutability;
use rustc_errors::{
- error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder,
+ error_code, pluralize, struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder,
ErrorGuaranteed, MultiSpan,
};
use rustc_hir as hir;
@@ -347,27 +347,35 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
let span_end = affix.last().unwrap().unwrap().0;
let span = span_start.to(span_end);
let cnt = affix.len();
- cx.tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, top, span, |lint| {
- let s = pluralize!(cnt);
- let mut diag = lint.build(&format!("{kind} irrefutable pattern{s} in let chain"));
- diag.note(&format!(
- "{these} pattern{s} will always match",
- these = pluralize!("this", cnt),
- ));
- diag.help(&format!(
- "consider moving {} {suggestion}",
- if cnt > 1 { "them" } else { "it" }
- ));
- diag.emit()
- });
+ let s = pluralize!(cnt);
+ cx.tcx.struct_span_lint_hir(
+ IRREFUTABLE_LET_PATTERNS,
+ top,
+ span,
+ format!("{kind} irrefutable pattern{s} in let chain"),
+ |lint| {
+ lint.note(format!(
+ "{these} pattern{s} will always match",
+ these = pluralize!("this", cnt),
+ ))
+ .help(format!(
+ "consider moving {} {suggestion}",
+ if cnt > 1 { "them" } else { "it" }
+ ))
+ },
+ );
};
if let Some(until) = chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) && until > 0 {
// The chain has a non-zero prefix of irrefutable `let` statements.
// Check if the let source is while, for there is no alternative place to put a prefix,
// and we shouldn't lint.
+ // For let guards inside a match, prefixes might use bindings of the match pattern,
+ // so can't always be moved out.
+ // FIXME: Add checking whether the bindings are actually used in the prefix,
+ // and lint if they are not.
let let_source = let_source_parent(self.tcx, top, None);
- if !matches!(let_source, LetSource::WhileLet) {
+ if !matches!(let_source, LetSource::WhileLet | LetSource::IfLetGuard) {
// Emit the lint
let prefix = &chain_refutabilities[..until];
lint_affix(prefix, "leading", "outside of the construct");
@@ -487,7 +495,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
],
Applicability::HasPlaceholders,
);
- if !bindings.is_empty() && cx.tcx.sess.is_nightly_build() {
+ if !bindings.is_empty() {
err.span_suggestion_verbose(
semi_span.shrink_to_lo(),
&format!(
@@ -561,26 +569,28 @@ fn check_for_bindings_named_same_as_variants(
BINDINGS_WITH_VARIANT_NAME,
p.hir_id,
p.span,
+ DelayDm(|| format!(
+ "pattern binding `{}` is named the same as one \
+ of the variants of the type `{}`",
+ ident, cx.tcx.def_path_str(edef.did())
+ )),
|lint| {
let ty_path = cx.tcx.def_path_str(edef.did());
- let mut err = lint.build(&format!(
- "pattern binding `{}` is named the same as one \
- of the variants of the type `{}`",
- ident, ty_path
- ));
- err.code(error_code!(E0170));
+ lint.code(error_code!(E0170));
+
// If this is an irrefutable pattern, and there's > 1 variant,
// then we can't actually match on this. Applying the below
// suggestion would produce code that breaks on `check_irrefutable`.
if rf == Refutable || variant_count == 1 {
- err.span_suggestion(
+ lint.span_suggestion(
p.span,
"to match on the variant, qualify the path",
format!("{}::{}", ty_path, ident),
Applicability::MachineApplicable,
);
}
- err.emit();
+
+ lint
},
)
}
@@ -598,14 +608,13 @@ fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
}
fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<Span>) {
- tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, |lint| {
- let mut err = lint.build("unreachable pattern");
+ tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, "unreachable pattern", |lint| {
if let Some(catchall) = catchall {
// We had a catchall pattern, hint at that.
- err.span_label(span, "unreachable pattern");
- err.span_label(catchall, "matches any value");
+ lint.span_label(span, "unreachable pattern");
+ lint.span_label(catchall, "matches any value");
}
- err.emit();
+ lint
});
}
@@ -621,6 +630,11 @@ fn irrefutable_let_patterns(
count: usize,
span: Span,
) {
+ let span = match source {
+ LetSource::LetElse(span) => span,
+ _ => span,
+ };
+
macro_rules! emit_diag {
(
$lint:expr,
@@ -630,18 +644,23 @@ fn irrefutable_let_patterns(
) => {{
let s = pluralize!(count);
let these = pluralize!("this", count);
- let mut diag = $lint.build(&format!("irrefutable {} pattern{s}", $source_name));
- diag.note(&format!("{these} pattern{s} will always match, so the {}", $note_sufix));
- diag.help(concat!("consider ", $help_sufix));
- diag.emit()
+ tcx.struct_span_lint_hir(
+ IRREFUTABLE_LET_PATTERNS,
+ id,
+ span,
+ format!("irrefutable {} pattern{s}", $source_name),
+ |lint| {
+ lint.note(&format!(
+ "{these} pattern{s} will always match, so the {}",
+ $note_sufix
+ ))
+ .help(concat!("consider ", $help_sufix))
+ },
+ )
}};
}
- let span = match source {
- LetSource::LetElse(span) => span,
- _ => span,
- };
- tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match source {
+ match source {
LetSource::GenericLet => {
emit_diag!(lint, "`let`", "`let` is useless", "removing `let`");
}
@@ -677,7 +696,7 @@ fn irrefutable_let_patterns(
"instead using a `loop { ... }` with a `let` inside it"
);
}
- });
+ };
}
fn is_let_irrefutable<'p, 'tcx>(
@@ -985,8 +1004,8 @@ fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>(
}
/// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`.
-fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId, span: Span) -> bool {
- !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env)
+fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId) -> bool {
+ !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx, cx.param_env)
}
/// Check that there are no borrow or move conflicts in `binding @ subpat` patterns.
@@ -1012,7 +1031,7 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
// Get the binding move, extract the mutability if by-ref.
let mut_outer = match typeck_results.extract_binding_mode(sess, pat.hir_id, pat.span) {
- Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id, pat.span) => {
+ Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id) => {
// We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`.
let mut conflicts_ref = Vec::new();
sub.each_binding(|_, hir_id, span, _| {
@@ -1051,7 +1070,7 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
(Mutability::Mut, Mutability::Mut) => conflicts_mut_mut.push((span, name)), // 2x `ref mut`.
_ => conflicts_mut_ref.push((span, name)), // `ref` + `ref mut` in either direction.
},
- Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id, span) => {
+ Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id) => {
conflicts_move.push((span, name)) // `ref mut?` + by-move conflict.
}
Some(ty::BindByValue(_)) | None => {} // `ref mut?` + by-copy is fine.
@@ -1136,10 +1155,14 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option<HirId>) -> L
let parent_parent = hir.get_parent_node(parent);
let parent_parent_node = hir.get(parent_parent);
- if let hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), span, .. }) =
- parent_parent_node
- {
- return LetSource::LetElse(*span);
+ match parent_parent_node {
+ hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), span, .. }) => {
+ return LetSource::LetElse(*span);
+ }
+ hir::Node::Arm(hir::Arm { guard: Some(hir::Guard::If(_)), .. }) => {
+ return LetSource::IfLetGuard;
+ }
+ _ => {}
}
let parent_parent_parent = hir.get_parent_node(parent_parent);
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 b58685e89..ad12e0116 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,3 +1,4 @@
+use rustc_errors::DelayDm;
use rustc_hir as hir;
use rustc_index::vec::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
@@ -27,14 +28,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
span: Span,
mir_structural_match_violation: bool,
) -> Box<Pat<'tcx>> {
- self.tcx.infer_ctxt().enter(|infcx| {
- let mut convert = ConstToPat::new(self, id, span, infcx);
- convert.to_pat(cv, mir_structural_match_violation)
- })
+ let infcx = self.tcx.infer_ctxt().build();
+ let mut convert = ConstToPat::new(self, id, span, infcx);
+ convert.to_pat(cv, mir_structural_match_violation)
}
}
-struct ConstToPat<'a, 'tcx> {
+struct ConstToPat<'tcx> {
id: hir::HirId,
span: Span,
param_env: ty::ParamEnv<'tcx>,
@@ -54,7 +54,7 @@ struct ConstToPat<'a, 'tcx> {
behind_reference: Cell<bool>,
// inference context used for checking `T: Structural` bounds.
- infcx: InferCtxt<'a, 'tcx>,
+ infcx: InferCtxt<'tcx>,
include_lint_checks: bool,
@@ -70,21 +70,19 @@ mod fallback_to_const_ref {
/// hoops to get a reference to the value.
pub(super) struct FallbackToConstRef(());
- pub(super) fn fallback_to_const_ref<'a, 'tcx>(
- c2p: &super::ConstToPat<'a, 'tcx>,
- ) -> FallbackToConstRef {
+ pub(super) fn fallback_to_const_ref<'tcx>(c2p: &super::ConstToPat<'tcx>) -> FallbackToConstRef {
assert!(c2p.behind_reference.get());
FallbackToConstRef(())
}
}
use fallback_to_const_ref::{fallback_to_const_ref, FallbackToConstRef};
-impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
+impl<'tcx> ConstToPat<'tcx> {
fn new(
pat_ctxt: &PatCtxt<'_, 'tcx>,
id: hir::HirId,
span: Span,
- infcx: InferCtxt<'a, 'tcx>,
+ infcx: InferCtxt<'tcx>,
) -> Self {
trace!(?pat_ctxt.typeck_results.hir_owner);
ConstToPat {
@@ -205,9 +203,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
self.id,
self.span,
- |lint| {
- lint.build(&msg).emit();
- },
+ msg,
+ |lint| lint,
);
} else {
debug!(
@@ -286,9 +283,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
id,
span,
- |lint| {
- lint.build("floating-point types cannot be used in patterns").emit();
- },
+ "floating-point types cannot be used in patterns",
+ |lint| lint,
);
}
PatKind::Constant { value: cv }
@@ -340,15 +336,15 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
id,
span,
- |lint| {
- let msg = format!(
+ DelayDm(|| {
+ format!(
"to use a constant of type `{}` in a pattern, \
`{}` must be annotated with `#[derive(PartialEq, Eq)]`",
cv.ty(),
cv.ty(),
- );
- lint.build(&msg).emit();
- },
+ )
+ }),
+ |lint| lint,
);
}
// Since we are behind a reference, we can just bubble the error up so we get a
@@ -488,7 +484,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
self.id,
self.span,
- |lint| {lint.build(&msg).emit();},
+ msg,
+ |lint| lint,
);
}
PatKind::Constant { value: cv }
@@ -509,7 +506,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
// convert the dereferenced constant to a pattern that is the sub-pattern of the
// deref pattern.
_ => {
- if !pointee_ty.is_sized(tcx.at(span), param_env) {
+ if !pointee_ty.is_sized(tcx, param_env) {
// `tcx.deref_mir_constant()` below will ICE with an unsized type
// (except slices, which are handled in a separate arm above).
let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty);
@@ -537,7 +534,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => {
PatKind::Constant { value: cv }
}
- ty::RawPtr(pointee) if pointee.ty.is_sized(tcx.at(span), param_env) => {
+ ty::RawPtr(pointee) if pointee.ty.is_sized(tcx, param_env) => {
PatKind::Constant { value: cv }
}
// FIXME: these can have very surprising behaviour where optimization levels or other
@@ -556,9 +553,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::POINTER_STRUCTURAL_MATCH,
id,
span,
- |lint| {
- lint.build(msg).emit();
- },
+ msg,
+ |lint| lint,
);
}
PatKind::Constant { value: cv }
@@ -594,9 +590,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH,
id,
span,
- |lint| {
- lint.build(&msg).emit();
- },
+ msg,
+ |lint| lint,
);
}
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 5105f059f..595abc8f6 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -299,10 +299,10 @@ impl IntRange {
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
hir_id,
pcx.span,
+ "multiple patterns overlap on their endpoints",
|lint| {
- let mut err = lint.build("multiple patterns overlap on their endpoints");
for (int_range, span) in overlaps {
- err.span_label(
+ lint.span_label(
span,
&format!(
"this range overlaps on `{}`...",
@@ -310,9 +310,9 @@ impl IntRange {
),
);
}
- err.span_label(pcx.span, "... with this range");
- err.note("you likely meant to write mutually exclusive ranges");
- err.emit();
+ lint.span_label(pcx.span, "... with this range");
+ lint.note("you likely meant to write mutually exclusive ranges");
+ lint
},
);
}
@@ -988,10 +988,12 @@ impl<'tcx> SplitWildcard<'tcx> {
.filter(|(_, v)| {
// If `exhaustive_patterns` is enabled, we exclude variants known to be
// uninhabited.
- let is_uninhabited = is_exhaustive_pat_feature
- && v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env)
- .contains(cx.tcx, cx.module);
- !is_uninhabited
+ !is_exhaustive_pat_feature
+ || v.inhabited_predicate(cx.tcx, *def).subst(cx.tcx, substs).apply(
+ cx.tcx,
+ cx.param_env,
+ cx.module,
+ )
})
.map(|(idx, _)| Variant(idx))
.collect();
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 0edf6a983..2526522a2 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -86,7 +86,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
// ```
//
// the type assigned to `Some(n)` in `unadjusted_pat` would be `Option<i32>` (this is
- // determined in rustc_typeck::check::match). The adjustments would be
+ // determined in rustc_hir_analysis::check::match). The adjustments would be
//
// `vec![&&Option<i32>, &Option<i32>]`.
//
@@ -200,6 +200,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
}
+ #[instrument(skip(self), level = "debug")]
fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
let mut ty = self.typeck_results.node_type(pat.hir_id);
let mut span = pat.span;
@@ -432,7 +433,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
| DefKind::AssocTy,
_,
)
- | Res::SelfTy { .. }
+ | Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. }
| Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
_ => {
let pattern_error = match res {
@@ -684,7 +686,7 @@ macro_rules! ClonePatternFoldableImpls {
}
ClonePatternFoldableImpls! { <'tcx>
- Span, Field, Mutability, Symbol, LocalVarId, usize, ty::Const<'tcx>,
+ Span, Field, Mutability, Symbol, LocalVarId, usize,
Region<'tcx>, Ty<'tcx>, BindingMode, AdtDef<'tcx>,
SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>,
UserTypeProjection, CanonicalUserTypeAnnotation<'tcx>
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 115d34ff8..8dc9976ea 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -746,7 +746,7 @@ impl<'p, 'tcx> Witness<'p, 'tcx> {
/// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
/// is not exhaustive enough.
///
-/// NB: The partner lint for structs lives in `compiler/rustc_typeck/src/check/pat.rs`.
+/// NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
scrut_ty: Ty<'tcx>,
@@ -754,9 +754,8 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
hir_id: HirId,
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
) {
- cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, |build| {
+ cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, "some variants are not matched explicitly", |lint| {
let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
- let mut lint = build.build("some variants are not matched explicitly");
lint.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
lint.help(
"ensure that all variants are matched explicitly by adding the suggested match arms",
@@ -765,7 +764,7 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
"the matched value is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
scrut_ty,
));
- lint.emit();
+ lint
});
}
@@ -842,7 +841,15 @@ fn is_useful<'p, 'tcx>(
}
}
} else {
- let ty = v.head().ty();
+ let mut ty = v.head().ty();
+
+ // Opaque types can't get destructured/split, but the patterns can
+ // actually hint at hidden types, so we use the patterns' types instead.
+ if let ty::Opaque(..) = ty.kind() {
+ if let Some(row) = rows.first() {
+ ty = row.head().ty();
+ }
+ }
let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
let pcx = &PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
@@ -878,7 +885,7 @@ fn is_useful<'p, 'tcx>(
// that has the potential to trigger the `non_exhaustive_omitted_patterns` lint.
// To understand the workings checkout `Constructor::split` and `SplitWildcard::new/into_ctors`
if is_non_exhaustive_and_wild
- // We check that the match has a wildcard pattern and that that wildcard is useful,
+ // We check that the match has a wildcard pattern and that wildcard is useful,
// meaning there are variants that are covered by the wildcard. Without the check
// for `witness_preference` the lint would trigger on `if let NonExhaustiveEnum::A = foo {}`
&& usefulness.is_useful() && matches!(witness_preference, RealArm)
diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml
index 385e9ba74..324644b67 100644
--- a/compiler/rustc_mir_dataflow/Cargo.toml
+++ b/compiler/rustc_mir_dataflow/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
polonius-engine = "0.13.0"
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index c0b0cc3c5..23403628c 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -823,9 +823,10 @@ where
// tmp = &raw mut P;
// cur = tmp as *mut T;
// end = Offset(cur, len);
+ let mir_cast_kind = ty::cast::mir_cast_kind(iter_ty, tmp_ty);
vec![
self.assign(tmp, Rvalue::AddressOf(Mutability::Mut, self.place)),
- self.assign(cur, Rvalue::Cast(CastKind::Misc, Operand::Move(tmp), iter_ty)),
+ self.assign(cur, Rvalue::Cast(mir_cast_kind, Operand::Move(tmp), iter_ty)),
self.assign(
length_or_end,
Rvalue::BinaryOp(
@@ -893,7 +894,7 @@ where
}
ty::Slice(ety) => self.open_drop_for_array(*ety, None),
- _ => bug!("open drop from non-ADT `{:?}`", ty),
+ _ => span_bug!(self.source_info.span, "open drop from non-ADT `{:?}`", ty),
}
}
diff --git a/compiler/rustc_mir_dataflow/src/errors.rs b/compiler/rustc_mir_dataflow/src/errors.rs
index cc1425787..cfacc0ec3 100644
--- a/compiler/rustc_mir_dataflow/src/errors.rs
+++ b/compiler/rustc_mir_dataflow/src/errors.rs
@@ -1,70 +1,70 @@
-use rustc_macros::SessionDiagnostic;
+use rustc_macros::Diagnostic;
use rustc_span::{Span, Symbol};
-#[derive(SessionDiagnostic)]
-#[diag(mir_dataflow::path_must_end_in_filename)]
+#[derive(Diagnostic)]
+#[diag(mir_dataflow_path_must_end_in_filename)]
pub(crate) struct PathMustEndInFilename {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(mir_dataflow::unknown_formatter)]
+#[derive(Diagnostic)]
+#[diag(mir_dataflow_unknown_formatter)]
pub(crate) struct UnknownFormatter {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(mir_dataflow::duplicate_values_for)]
+#[derive(Diagnostic)]
+#[diag(mir_dataflow_duplicate_values_for)]
pub(crate) struct DuplicateValuesFor {
#[primary_span]
pub span: Span,
pub name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(mir_dataflow::requires_an_argument)]
+#[derive(Diagnostic)]
+#[diag(mir_dataflow_requires_an_argument)]
pub(crate) struct RequiresAnArgument {
#[primary_span]
pub span: Span,
pub name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(mir_dataflow::stop_after_dataflow_ended_compilation)]
+#[derive(Diagnostic)]
+#[diag(mir_dataflow_stop_after_dataflow_ended_compilation)]
pub(crate) struct StopAfterDataFlowEndedCompilation;
-#[derive(SessionDiagnostic)]
-#[diag(mir_dataflow::peek_must_be_place_or_ref_place)]
+#[derive(Diagnostic)]
+#[diag(mir_dataflow_peek_must_be_place_or_ref_place)]
pub(crate) struct PeekMustBePlaceOrRefPlace {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(mir_dataflow::peek_must_be_not_temporary)]
+#[derive(Diagnostic)]
+#[diag(mir_dataflow_peek_must_be_not_temporary)]
pub(crate) struct PeekMustBeNotTemporary {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(mir_dataflow::peek_bit_not_set)]
+#[derive(Diagnostic)]
+#[diag(mir_dataflow_peek_bit_not_set)]
pub(crate) struct PeekBitNotSet {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(mir_dataflow::peek_argument_not_a_local)]
+#[derive(Diagnostic)]
+#[diag(mir_dataflow_peek_argument_not_a_local)]
pub(crate) struct PeekArgumentNotALocal {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(mir_dataflow::peek_argument_untracked)]
+#[derive(Diagnostic)]
+#[diag(mir_dataflow_peek_argument_untracked)]
pub(crate) struct PeekArgumentUntracked {
#[primary_span]
pub span: Span,
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index b45c32ee9..b471d04fd 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -1,7 +1,6 @@
#![feature(associated_type_defaults)]
#![feature(box_patterns)]
#![feature(exact_size_is_empty)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(min_specialization)]
#![feature(once_cell)]
#![feature(stmt_expr_attributes)]
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
index 28936274b..7806e8f45 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
@@ -48,6 +48,7 @@ impl<'tcx> Lift for PlaceElem<'tcx> {
match *self {
ProjectionElem::Deref => ProjectionElem::Deref,
ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty.lift()),
+ ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty.lift()),
ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()),
ProjectionElem::Subslice { from, to, from_end } => {
ProjectionElem::Subslice { from, to, from_end }
diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml
index 85b7a4af5..53545cff0 100644
--- a/compiler/rustc_mir_transform/Cargo.toml
+++ b/compiler/rustc_mir_transform/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
itertools = "0.10.1"
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 8838b14c5..fa5f392fa 100644
--- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
+++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
@@ -1,4 +1,4 @@
-use rustc_errors::{DiagnosticBuilder, LintDiagnosticBuilder};
+use rustc_errors::{DiagnosticBuilder, DiagnosticMessage};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
@@ -63,7 +63,10 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
place: &Place<'tcx>,
const_item: DefId,
location: Location,
- decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b, ()>) -> DiagnosticBuilder<'b, ()>,
+ msg: impl Into<DiagnosticMessage>,
+ decorate: impl for<'a, 'b> FnOnce(
+ &'a mut DiagnosticBuilder<'b, ()>,
+ ) -> &'a mut DiagnosticBuilder<'b, ()>,
) {
// Don't lint on borrowing/assigning when a dereference is involved.
// If we 'leave' the temporary via a dereference, we must
@@ -84,10 +87,10 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
CONST_ITEM_MUTATION,
lint_root,
source_info.span,
+ msg,
|lint| {
decorate(lint)
.span_note(self.tcx.def_span(const_item), "`const` item defined here")
- .emit();
},
);
}
@@ -102,10 +105,8 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
// 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, |lint| {
- let mut lint = lint.build("attempting to modify a `const` item");
- lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified");
- lint
+ 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")
})
}
}
@@ -137,8 +138,7 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
});
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, |lint| {
- let mut lint = lint.build("taking a mutable reference to a `const` item");
+ 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");
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index 3b7ba3f9a..51abcf511 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -33,21 +33,27 @@ struct PackedRefChecker<'a, 'tcx> {
fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- tcx.struct_span_lint_hir(UNALIGNED_REFERENCES, lint_hir_id, tcx.def_span(def_id), |lint| {
- // FIXME: when we make this a hard error, this should have its
- // own error code.
- let extra = if tcx.generics_of(def_id).own_requires_monomorphization() {
- "with type or const parameters"
- } else {
- "that does not derive `Copy`"
- };
- let message = format!(
- "`{}` can't be derived on this `#[repr(packed)]` struct {}",
- tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")),
- extra
- );
- lint.build(message).emit();
- });
+ // FIXME: when we make this a hard error, this should have its
+ // own error code.
+
+ let extra = if tcx.generics_of(def_id).own_requires_monomorphization() {
+ "with type or const parameters"
+ } else {
+ "that does not derive `Copy`"
+ };
+ let message = format!(
+ "`{}` can't be derived on this `#[repr(packed)]` struct {}",
+ tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")),
+ extra
+ );
+
+ tcx.struct_span_lint_hir(
+ UNALIGNED_REFERENCES,
+ lint_hir_id,
+ tcx.def_span(def_id),
+ message,
+ |lint| lint,
+ );
}
impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
@@ -86,8 +92,9 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
UNALIGNED_REFERENCES,
lint_root,
source_info.span,
+ "reference to packed field is unaligned",
|lint| {
- lint.build("reference to packed field is unaligned")
+ lint
.note(
"fields of packed structs are not properly aligned, and creating \
a misaligned reference is undefined behavior (even if that \
@@ -98,7 +105,6 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
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();
},
);
}
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index beff19a3a..f8f04214a 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -312,7 +312,7 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> {
} else if !place
.ty(self.body, self.tcx)
.ty
- .is_freeze(self.tcx.at(self.source_info.span), self.param_env)
+ .is_freeze(self.tcx, self.param_env)
{
UnsafetyViolationDetails::BorrowOfLayoutConstrainedField
} else {
@@ -489,21 +489,20 @@ fn unsafety_check_result<'tcx>(
fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id));
- tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, |lint| {
- let msg = "unnecessary `unsafe` block";
- let mut db = lint.build(msg);
- db.span_label(span, msg);
+ 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) => {
- db.span_label(
+ lint.span_label(
tcx.sess.source_map().guess_head_span(tcx.hir().span(id)),
"because it's nested under this `unsafe` block",
);
}
}
- db.emit();
+ lint
});
}
@@ -543,15 +542,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
UNSAFE_OP_IN_UNSAFE_FN,
lint_root,
source_info.span,
- |lint| {
- lint.build(&format!(
- "{} is unsafe and requires unsafe block (error E0133)",
- description,
- ))
- .span_label(source_info.span, description)
- .note(note)
- .emit();
- },
+ format!("{} is unsafe and requires unsafe block (error E0133)", description,),
+ |lint| lint.span_label(source_info.span, description).note(note),
),
}
}
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 7a2a15a84..4e4515888 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -17,7 +17,7 @@ use rustc_middle::mir::{
RETURN_PLACE,
};
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable};
use rustc_span::{def_id::DefId, Span};
use rustc_target::abi::{self, HasDataLayout, Size, TargetDataLayout};
@@ -471,7 +471,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
return None;
}
- self.ecx.mir_const_to_op(&c.literal, None).ok()
+ self.ecx.const_to_op(&c.literal, None).ok()
}
/// Returns the value, if any, of evaluating `place`.
@@ -633,7 +633,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
}
if !rvalue
.ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx)
- .is_sized(self.ecx.tcx, self.param_env)
+ .is_sized(*self.ecx.tcx, self.param_env)
{
// the interpreter doesn't support unsized locals (only unsized arguments),
// but rustc does (in a kinda broken way), so we have to skip them here
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 37e78f4ac..479c4e577 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -16,12 +16,12 @@ use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{
- AssertKind, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, Location, Operand, Place,
- Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator,
- TerminatorKind, UnOp, RETURN_PLACE,
+ AssertKind, BinOp, Body, Constant, Local, LocalDecl, Location, Operand, Place, Rvalue,
+ SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind,
+ UnOp, RETURN_PLACE,
};
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::{self, ConstInt, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitable};
use rustc_session::lint;
use rustc_span::Span;
@@ -286,39 +286,22 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
}
/// Returns the value, if any, of evaluating `c`.
- fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Option<OpTy<'tcx>> {
+ fn eval_constant(
+ &mut self,
+ c: &Constant<'tcx>,
+ _source_info: SourceInfo,
+ ) -> Option<OpTy<'tcx>> {
// FIXME we need to revisit this for #67176
if c.needs_subst() {
return None;
}
- match self.ecx.mir_const_to_op(&c.literal, None) {
+ match self.ecx.const_to_op(&c.literal, None) {
Ok(op) => Some(op),
Err(error) => {
let tcx = self.ecx.tcx.at(c.span);
let err = ConstEvalErr::new(&self.ecx, error, Some(c.span));
- if let Some(lint_root) = self.lint_root(source_info) {
- let lint_only = match c.literal {
- ConstantKind::Ty(ct) => ct.needs_subst(),
- ConstantKind::Unevaluated(
- ty::Unevaluated { def: _, substs: _, promoted: Some(_) },
- _,
- ) => {
- // Promoteds must lint and not error as the user didn't ask for them
- true
- }
- ConstantKind::Unevaluated(..) | ConstantKind::Val(..) => c.needs_subst(),
- };
- if lint_only {
- // Out of backwards compatibility we cannot report hard errors in unused
- // generic functions using associated constants of the generic parameters.
- err.report_as_lint(tcx, "erroneous constant used", lint_root, Some(c.span));
- } else {
- err.report_as_error(tcx, "erroneous constant used");
- }
- } else {
- err.report_as_error(tcx, "erroneous constant used");
- }
+ err.report_as_error(tcx, "erroneous constant used");
None
}
}
@@ -347,10 +330,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
panic: AssertKind<impl std::fmt::Debug>,
) {
if let Some(lint_root) = self.lint_root(source_info) {
- self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| {
- let mut err = lint.build(message);
- err.span_label(source_info.span, format!("{:?}", panic));
- err.emit();
+ self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, message, |lint| {
+ lint.span_label(source_info.span, format!("{:?}", panic))
});
}
}
@@ -519,7 +500,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
}
if !rvalue
.ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx)
- .is_sized(self.ecx.tcx, self.param_env)
+ .is_sized(*self.ecx.tcx, self.param_env)
{
// the interpreter doesn't support unsized locals (only unsized arguments),
// but rustc does (in a kinda broken way), so we have to skip them here
diff --git a/compiler/rustc_mir_transform/src/coverage/test_macros/Cargo.toml b/compiler/rustc_mir_transform/src/coverage/test_macros/Cargo.toml
index f5e8b6565..f753caa91 100644
--- a/compiler/rustc_mir_transform/src/coverage/test_macros/Cargo.toml
+++ b/compiler/rustc_mir_transform/src/coverage/test_macros/Cargo.toml
@@ -5,4 +5,3 @@ edition = "2021"
[lib]
proc-macro = true
-doctest = false
diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
new file mode 100644
index 000000000..28b1c5a48
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
@@ -0,0 +1,248 @@
+//! Deduces supplementary parameter attributes from MIR.
+//!
+//! Deduced parameter attributes are those that can only be soundly determined by examining the
+//! body of the function instead of just the signature. These can be useful for optimization
+//! purposes on a best-effort basis. We compute them here and store them into the crate metadata so
+//! dependent crates can use them.
+
+use rustc_hir::def_id::DefId;
+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_session::config::OptLevel;
+
+/// A visitor that determines which arguments have been mutated. We can't use the mutability field
+/// on LocalDecl for this because it has no meaning post-optimization.
+struct DeduceReadOnly {
+ /// Each bit is indexed by argument number, starting at zero (so 0 corresponds to local decl
+ /// 1). The bit is true if the argument may have been mutated or false if we know it hasn't
+ /// been up to the point we're at.
+ mutable_args: BitSet<usize>,
+}
+
+impl DeduceReadOnly {
+ /// Returns a new DeduceReadOnly instance.
+ fn new(arg_count: usize) -> Self {
+ Self { mutable_args: BitSet::new_empty(arg_count) }
+ }
+}
+
+impl<'tcx> Visitor<'tcx> for DeduceReadOnly {
+ fn visit_local(&mut self, local: Local, mut context: PlaceContext, _: Location) {
+ // We're only interested in arguments.
+ if local == RETURN_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) => {
+ // This is a mutation, so mark it as such.
+ self.mutable_args.insert(local.index() - 1);
+ }
+ PlaceContext::NonMutatingUse(..) | PlaceContext::NonUse(..) => {
+ // Not mutating, so it's fine.
+ }
+ }
+ }
+
+ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
+ // OK, this is subtle. Suppose that we're trying to deduce whether `x` in `f` is read-only
+ // and we have the following:
+ //
+ // fn f(x: BigStruct) { g(x) }
+ // fn g(mut y: BigStruct) { y.foo = 1 }
+ //
+ // If, at the generated MIR level, `f` turned into something like:
+ //
+ // fn f(_1: BigStruct) -> () {
+ // let mut _0: ();
+ // bb0: {
+ // _0 = g(move _1) -> bb1;
+ // }
+ // ...
+ // }
+ //
+ // then it would be incorrect to mark `x` (i.e. `_1`) as `readonly`, because `g`'s write to
+ // its copy of the indirect parameter would actually be a write directly to the pointer that
+ // `f` passes. Note that function arguments are the only situation in which this problem can
+ // arise: every other use of `move` in MIR doesn't actually write to the value it moves
+ // from.
+ //
+ // Anyway, right now this situation doesn't actually arise in practice. Instead, the MIR for
+ // that function looks like this:
+ //
+ // fn f(_1: BigStruct) -> () {
+ // let mut _0: ();
+ // let mut _2: BigStruct;
+ // bb0: {
+ // _2 = move _1;
+ // _0 = g(move _2) -> bb1;
+ // }
+ // ...
+ // }
+ //
+ // Because of that extra move that MIR construction inserts, `x` (i.e. `_1`) can *in
+ // practice* safely be marked `readonly`.
+ //
+ // To handle the possibility that other optimizations (for example, destination propagation)
+ // might someday generate MIR like the first example above, we panic upon seeing an argument
+ // to *our* function that is directly moved into *another* function as an argument. Having
+ // eliminated that problematic case, we can safely treat moves as copies in this analysis.
+ //
+ // In the future, if MIR optimizations cause arguments of a caller to be directly moved into
+ // the argument of a callee, we can just add that argument to `mutated_args` instead of
+ // panicking.
+ //
+ // Note that, because the problematic MIR is never actually generated, we can't add a test
+ // case for this.
+
+ if let TerminatorKind::Call { ref args, .. } = terminator.kind {
+ for arg in args {
+ if let Operand::Move(_) = *arg {
+ // ArgumentChecker panics if a direct move of an argument from a caller to a
+ // callee was detected.
+ //
+ // If, in the future, MIR optimizations cause arguments to be moved directly
+ // from callers to callees, change the panic to instead add the argument in
+ // question to `mutating_uses`.
+ ArgumentChecker::new(self.mutable_args.domain_size())
+ .visit_operand(arg, location)
+ }
+ }
+ };
+
+ self.super_terminator(terminator, location);
+ }
+}
+
+/// A visitor that simply panics if a direct move of an argument from a caller to a callee was
+/// detected.
+struct ArgumentChecker {
+ /// The number of arguments to the calling function.
+ arg_count: usize,
+}
+
+impl ArgumentChecker {
+ /// Creates a new ArgumentChecker.
+ fn new(arg_count: usize) -> Self {
+ Self { arg_count }
+ }
+}
+
+impl<'tcx> Visitor<'tcx> for ArgumentChecker {
+ fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
+ // Check to make sure that, if this local is an argument, we didn't move directly from it.
+ if matches!(context, PlaceContext::NonMutatingUse(NonMutatingUseContext::Move))
+ && local != RETURN_PLACE
+ && local.index() <= self.arg_count
+ {
+ // If, in the future, MIR optimizations cause arguments to be moved directly from
+ // callers to callees, change this panic to instead add the argument in question to
+ // `mutating_uses`.
+ panic!("Detected a direct move from a caller's argument to a callee's argument!")
+ }
+ }
+}
+
+/// Returns true if values of a given type will never be passed indirectly, regardless of ABI.
+fn type_will_always_be_passed_directly<'tcx>(ty: Ty<'tcx>) -> bool {
+ matches!(
+ ty.kind(),
+ ty::Bool
+ | ty::Char
+ | ty::Float(..)
+ | ty::Int(..)
+ | ty::RawPtr(..)
+ | ty::Ref(..)
+ | ty::Slice(..)
+ | ty::Uint(..)
+ )
+}
+
+/// Returns the deduced parameter attributes for a function.
+///
+/// Deduced parameter attributes are those that can only be soundly determined by examining the
+/// body of the function instead of just the signature. These can be useful for optimization
+/// purposes on a best-effort basis. We compute them here and store them into the crate metadata so
+/// dependent crates can use them.
+pub fn deduced_param_attrs<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [DeducedParamAttrs] {
+ // This computation is unfortunately rather expensive, so don't do it unless we're optimizing.
+ // Also skip it in incremental mode.
+ if tcx.sess.opts.optimize == OptLevel::No || tcx.sess.opts.incremental.is_some() {
+ return &[];
+ }
+
+ // If the Freeze language item isn't present, then don't bother.
+ if tcx.lang_items().freeze_trait().is_none() {
+ return &[];
+ }
+
+ // Codegen won't use this information for anything if all the function parameters are passed
+ // directly. Detect that and bail, for compilation speed.
+ let fn_ty = tcx.type_of(def_id);
+ if matches!(fn_ty.kind(), ty::FnDef(..)) {
+ if fn_ty
+ .fn_sig(tcx)
+ .inputs()
+ .skip_binder()
+ .iter()
+ .cloned()
+ .all(type_will_always_be_passed_directly)
+ {
+ return &[];
+ }
+ }
+
+ // Don't deduce any attributes for functions that have no MIR.
+ if !tcx.is_mir_available(def_id) {
+ return &[];
+ }
+
+ // Deduced attributes for other crates should be read from the metadata instead of via this
+ // function.
+ debug_assert!(def_id.is_local());
+
+ // Grab the optimized MIR. Analyze it to determine which arguments have been mutated.
+ let body: &Body<'tcx> = tcx.optimized_mir(def_id);
+ let mut deduce_read_only = DeduceReadOnly::new(body.arg_count);
+ deduce_read_only.visit_body(body);
+
+ // Set the `readonly` attribute for every argument that we concluded is immutable and that
+ // contains no UnsafeCells.
+ //
+ // FIXME: This is overly conservative around generic parameters: `is_freeze()` will always
+ // return false for them. For a description of alternatives that could do a better job here,
+ // see [1].
+ //
+ // [1]: https://github.com/rust-lang/rust/pull/103172#discussion_r999139997
+ 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()),
+ },
+ ),
+ );
+
+ // Trailing parameters past the size of the `deduced_param_attrs` array are assumed to have the
+ // default set of attributes, so we don't have to store them explicitly. Pop them off to save a
+ // few bytes in metadata.
+ while deduced_param_attrs.last() == Some(&DeducedParamAttrs::default()) {
+ let last_index = deduced_param_attrs.len() - 1;
+ deduced_param_attrs = &mut deduced_param_attrs[0..last_index];
+ }
+
+ deduced_param_attrs
+}
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index 294af2455..ef8d6bb65 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -8,7 +8,6 @@ use rustc_index::vec::Idx;
use rustc_middle::mir::patch::MirPatch;
use rustc_middle::mir::visit::MutVisitor;
use rustc_middle::mir::*;
-use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{Ty, TyCtxt};
/// Constructs the types used when accessing a Box's pointer
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
index 7522a50a8..1244c1802 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -106,14 +106,12 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
.lint_root;
let span = terminator.source_info.span;
- tcx.struct_span_lint_hir(FFI_UNWIND_CALLS, lint_root, span, |lint| {
- let msg = match fn_def_id {
- Some(_) => "call to foreign function with FFI-unwind ABI",
- None => "call to function pointer with FFI-unwind ABI",
- };
- let mut db = lint.build(msg);
- db.span_label(span, msg);
- db.emit();
+ 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)
});
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 2e4fe1e3e..469566694 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -3,11 +3,7 @@ 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,
- subst::{GenericArgKind, Subst, SubstsRef},
- EarlyBinder, PredicateKind, Ty, TyCtxt,
-};
+use rustc_middle::ty::{self, EarlyBinder, GenericArgKind, PredicateKind, SubstsRef, Ty, TyCtxt};
use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES;
use rustc_span::{symbol::sym, Span};
use rustc_target::spec::abi::Abi;
@@ -183,11 +179,15 @@ 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(FUNCTION_ITEM_REFERENCES, lint_root, span, |lint| {
- lint.build("taking a reference to a function item does not give a function pointer")
- .span_suggestion(
+ self.tcx.struct_span_lint_hir(
+ 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!("cast `{}` to obtain a function pointer", ident),
format!(
"{} as {}{}fn({}{}){}",
if params.is_empty() { ident } else { format!("{}::<{}>", ident, params) },
@@ -199,7 +199,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
),
Applicability::Unspecified,
)
- .emit();
- });
+ },
+ );
}
}
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 705cf776f..c833de3a8 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -61,9 +61,8 @@ use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::mir::dump_mir;
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
use rustc_middle::mir::*;
-use rustc_middle::ty::subst::{Subst, SubstsRef};
-use rustc_middle::ty::GeneratorSubsts;
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
+use rustc_middle::ty::{GeneratorSubsts, SubstsRef};
use rustc_mir_dataflow::impls::{
MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
};
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index d00a384cb..780b91d92 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -7,7 +7,6 @@ use rustc_index::vec::Idx;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
-use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
use rustc_session::config::OptLevel;
use rustc_span::def_id::DefId;
@@ -606,7 +605,7 @@ impl<'tcx> Inliner<'tcx> {
caller_body.required_consts.extend(
callee_body.required_consts.iter().copied().filter(|&ct| match ct.literal {
ConstantKind::Ty(_) => {
- bug!("should never encounter ty::Unevaluated in `required_consts`")
+ bug!("should never encounter ty::UnevaluatedConst in `required_consts`")
}
ConstantKind::Val(..) | ConstantKind::Unevaluated(..) => true,
}),
@@ -978,6 +977,21 @@ impl Integrator<'_, '_> {
trace!("mapping block `{:?}` to `{:?}`", block, new);
new
}
+
+ fn map_unwind(&self, unwind: Option<BasicBlock>) -> Option<BasicBlock> {
+ if self.in_cleanup_block {
+ if unwind.is_some() {
+ bug!("cleanup on cleanup block");
+ }
+ return unwind;
+ }
+
+ match unwind {
+ Some(target) => Some(self.map_block(target)),
+ // Add an unwind edge to the original call's cleanup block
+ None => self.cleanup_block,
+ }
+ }
}
impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
@@ -1086,35 +1100,17 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
TerminatorKind::Drop { ref mut target, ref mut unwind, .. }
| TerminatorKind::DropAndReplace { ref mut target, ref mut unwind, .. } => {
*target = self.map_block(*target);
- if let Some(tgt) = *unwind {
- *unwind = Some(self.map_block(tgt));
- } else if !self.in_cleanup_block {
- // Unless this drop is in a cleanup block, add an unwind edge to
- // the original call's cleanup block
- *unwind = self.cleanup_block;
- }
+ *unwind = self.map_unwind(*unwind);
}
TerminatorKind::Call { ref mut target, ref mut cleanup, .. } => {
if let Some(ref mut tgt) = *target {
*tgt = self.map_block(*tgt);
}
- if let Some(tgt) = *cleanup {
- *cleanup = Some(self.map_block(tgt));
- } else if !self.in_cleanup_block {
- // Unless this call is in a cleanup block, add an unwind edge to
- // the original call's cleanup block
- *cleanup = self.cleanup_block;
- }
+ *cleanup = self.map_unwind(*cleanup);
}
TerminatorKind::Assert { ref mut target, ref mut cleanup, .. } => {
*target = self.map_block(*target);
- if let Some(tgt) = *cleanup {
- *cleanup = Some(self.map_block(tgt));
- } else if !self.in_cleanup_block {
- // Unless this assert is in a cleanup block, add an unwind edge to
- // the original call's cleanup block
- *cleanup = self.cleanup_block;
- }
+ *cleanup = self.map_unwind(*cleanup);
}
TerminatorKind::Return => {
terminator.kind = if let Some(tgt) = self.callsite.target {
@@ -1142,11 +1138,8 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
TerminatorKind::InlineAsm { ref mut destination, ref mut cleanup, .. } => {
if let Some(ref mut tgt) = *destination {
*tgt = self.map_block(*tgt);
- } else if !self.in_cleanup_block {
- // Unless this inline asm is in a cleanup block, add an unwind edge to
- // the original call's cleanup block
- *cleanup = self.cleanup_block;
}
+ *cleanup = self.map_unwind(*cleanup);
}
}
}
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index e6fc85595..5be223254 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -1,7 +1,6 @@
#![allow(rustc::potential_query_instability)]
#![feature(box_patterns)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(map_try_insert)]
#![feature(min_specialization)]
#![feature(never_type)]
@@ -57,6 +56,7 @@ mod const_prop_lint;
mod coverage;
mod dead_store_elimination;
mod deaggregator;
+mod deduce_param_attrs;
mod deduplicate_blocks;
mod deref_separator;
mod dest_prop;
@@ -71,7 +71,6 @@ mod inline;
mod instcombine;
mod lower_intrinsics;
mod lower_slice_len;
-mod marker;
mod match_branches;
mod multiple_return_terminators;
mod normalize_array_len;
@@ -140,6 +139,7 @@ pub fn provide(providers: &mut Providers) {
promoted_mir_of_const_arg: |tcx, (did, param_did)| {
promoted_mir(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
},
+ deduced_param_attrs: deduce_param_attrs::deduced_param_attrs,
..*providers
};
}
@@ -302,6 +302,7 @@ fn mir_const<'tcx>(
&simplify::SimplifyCfg::new("initial"),
&rustc_peek::SanityCheck, // Just a lint
],
+ None,
);
tcx.alloc_steal_mir(body)
}
@@ -341,6 +342,7 @@ fn mir_promoted<'tcx>(
&simplify::SimplifyCfg::new("promote-consts"),
&coverage::InstrumentCoverage,
],
+ Some(MirPhase::Analysis(AnalysisPhase::Initial)),
);
let promoted = promote_pass.promoted_fragments.into_inner();
@@ -408,10 +410,8 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
pm::run_passes(
tcx,
&mut body,
- &[
- &const_prop::ConstProp,
- &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)),
- ],
+ &[&const_prop::ConstProp],
+ Some(MirPhase::Runtime(RuntimePhase::Optimized)),
);
}
}
@@ -473,6 +473,7 @@ fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>
&remove_uninit_drops::RemoveUninitDrops,
&simplify::SimplifyCfg::new("remove-false-edges"),
],
+ None,
);
check_consts::post_drop_elaboration::check_live_drops(tcx, &body); // FIXME: make this a MIR lint
}
@@ -497,10 +498,9 @@ fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&cleanup_post_borrowck::CleanupNonCodegenStatements,
&simplify::SimplifyCfg::new("early-opt"),
&deref_separator::Derefer,
- &marker::PhaseChange(MirPhase::Analysis(AnalysisPhase::PostCleanup)),
];
- pm::run_passes(tcx, body, passes);
+ pm::run_passes(tcx, body, passes, Some(MirPhase::Analysis(AnalysisPhase::PostCleanup)));
}
/// Returns the sequence of passes that lowers analysis to runtime MIR.
@@ -525,9 +525,8 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// CTFE support for aggregates.
&deaggregator::Deaggregator,
&Lint(const_prop_lint::ConstProp),
- &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Initial)),
];
- pm::run_passes_no_validate(tcx, body, passes);
+ pm::run_passes_no_validate(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::Initial)));
}
/// Returns the sequence of passes that do the initial cleanup of runtime MIR.
@@ -536,10 +535,9 @@ fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&elaborate_box_derefs::ElaborateBoxDerefs,
&lower_intrinsics::LowerIntrinsics,
&simplify::SimplifyCfg::new("elaborate-drops"),
- &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::PostCleanup)),
];
- pm::run_passes(tcx, body, passes);
+ pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup)));
}
fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
@@ -590,10 +588,10 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&deduplicate_blocks::DeduplicateBlocks,
// Some cleanup necessary at least for LLVM and potentially other codegen backends.
&add_call_guards::CriticalCallEdges,
- &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)),
// Dump the end result for testing and debugging purposes.
&dump_mir::Marker("PreCodegen"),
],
+ Some(MirPhase::Runtime(RuntimePhase::Optimized)),
);
}
diff --git a/compiler/rustc_mir_transform/src/marker.rs b/compiler/rustc_mir_transform/src/marker.rs
deleted file mode 100644
index 06819fc1d..000000000
--- a/compiler/rustc_mir_transform/src/marker.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use std::borrow::Cow;
-
-use crate::MirPass;
-use rustc_middle::mir::{Body, MirPhase};
-use rustc_middle::ty::TyCtxt;
-
-/// Changes the MIR phase without changing the MIR itself.
-pub struct PhaseChange(pub MirPhase);
-
-impl<'tcx> MirPass<'tcx> for PhaseChange {
- fn phase_change(&self) -> Option<MirPhase> {
- Some(self.0)
- }
-
- fn name(&self) -> Cow<'_, str> {
- Cow::from(format!("PhaseChange-{:?}", self.0))
- }
-
- fn run_pass(&self, _: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}
-}
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
index 67dae7146..230c6a7cb 100644
--- a/compiler/rustc_mir_transform/src/pass_manager.rs
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -66,10 +66,6 @@ where
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
self.1.run_pass(tcx, body)
}
-
- fn phase_change(&self) -> Option<MirPhase> {
- self.1.phase_change()
- }
}
/// Run the sequence of passes without validating the MIR after each pass. The MIR is still
@@ -78,23 +74,28 @@ pub fn run_passes_no_validate<'tcx>(
tcx: TyCtxt<'tcx>,
body: &mut Body<'tcx>,
passes: &[&dyn MirPass<'tcx>],
+ phase_change: Option<MirPhase>,
) {
- run_passes_inner(tcx, body, passes, false);
+ run_passes_inner(tcx, body, passes, phase_change, false);
}
-pub fn run_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn MirPass<'tcx>]) {
- run_passes_inner(tcx, body, passes, true);
+/// The optional `phase_change` is applied after executing all the passes, if present
+pub fn run_passes<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ body: &mut Body<'tcx>,
+ passes: &[&dyn MirPass<'tcx>],
+ phase_change: Option<MirPhase>,
+) {
+ run_passes_inner(tcx, body, passes, phase_change, true);
}
fn run_passes_inner<'tcx>(
tcx: TyCtxt<'tcx>,
body: &mut Body<'tcx>,
passes: &[&dyn MirPass<'tcx>],
+ phase_change: Option<MirPhase>,
validate_each: bool,
) {
- let start_phase = body.phase;
- let mut cnt = 0;
-
let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir;
let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
trace!(?overridden_passes);
@@ -102,7 +103,6 @@ fn run_passes_inner<'tcx>(
for pass in passes {
let name = pass.name();
- // Gather information about what we should be doing for this pass
let overridden =
overridden_passes.iter().rev().find(|(s, _)| s == &*name).map(|(_name, polarity)| {
trace!(
@@ -112,32 +112,44 @@ fn run_passes_inner<'tcx>(
);
*polarity
});
- let is_enabled = overridden.unwrap_or_else(|| pass.is_enabled(&tcx.sess));
- let new_phase = pass.phase_change();
- let dump_enabled = (is_enabled && pass.is_mir_dump_enabled()) || new_phase.is_some();
- let validate = (validate && is_enabled)
- || new_phase == Some(MirPhase::Runtime(RuntimePhase::Optimized));
+ if !overridden.unwrap_or_else(|| pass.is_enabled(&tcx.sess)) {
+ continue;
+ }
+
+ let dump_enabled = pass.is_mir_dump_enabled();
if dump_enabled {
- dump_mir(tcx, body, start_phase, &name, cnt, false);
- }
- if is_enabled {
- pass.run_pass(tcx, body);
+ dump_mir_for_pass(tcx, body, &name, false);
}
- if dump_enabled {
- dump_mir(tcx, body, start_phase, &name, cnt, true);
- cnt += 1;
+ if validate {
+ validate_body(tcx, body, format!("before pass {}", name));
}
- if let Some(new_phase) = pass.phase_change() {
- if body.phase >= new_phase {
- panic!("Invalid MIR phase transition from {:?} to {:?}", body.phase, new_phase);
- }
- body.phase = new_phase;
+ pass.run_pass(tcx, body);
+
+ if dump_enabled {
+ dump_mir_for_pass(tcx, body, &name, true);
}
if validate {
validate_body(tcx, body, format!("after pass {}", name));
}
+
+ body.pass_count += 1;
+ }
+
+ if let Some(new_phase) = phase_change {
+ if body.phase >= new_phase {
+ panic!("Invalid MIR phase transition from {:?} to {:?}", body.phase, new_phase);
+ }
+
+ body.phase = new_phase;
+
+ dump_mir_for_phase_change(tcx, body);
+ if validate || new_phase == MirPhase::Runtime(RuntimePhase::Optimized) {
+ validate_body(tcx, body, format!("after phase change to {}", new_phase));
+ }
+
+ body.pass_count = 1;
}
}
@@ -145,22 +157,33 @@ pub fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: Strin
validate::Validator { when, mir_phase: body.phase }.run_pass(tcx, body);
}
-pub fn dump_mir<'tcx>(
+pub fn dump_mir_for_pass<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
- phase: MirPhase,
pass_name: &str,
- cnt: usize,
is_after: bool,
) {
- let phase_index = phase.phase_index();
+ let phase_index = body.phase.phase_index();
mir::dump_mir(
tcx,
- Some(&format_args!("{:03}-{:03}", phase_index, cnt)),
+ Some(&format_args!("{:03}-{:03}", phase_index, body.pass_count)),
pass_name,
if is_after { &"after" } else { &"before" },
body,
|_, _| Ok(()),
);
}
+
+pub fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+ let phase_index = body.phase.phase_index();
+
+ mir::dump_mir(
+ tcx,
+ Some(&format_args!("{:03}-000", phase_index)),
+ &format!("{}", body.phase),
+ &"after",
+ body,
+ |_, _| Ok(()),
+ )
+}
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 882136200..4e8798b7a 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -3,7 +3,7 @@ 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::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::{self, EarlyBinder, GeneratorSubsts, Ty, TyCtxt};
use rustc_target::abi::VariantIdx;
@@ -17,7 +17,7 @@ use std::iter;
use crate::util::expand_aggregate;
use crate::{
- abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator, marker,
+ abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator,
pass_manager as pm, remove_noop_landing_pads, simplify,
};
use rustc_middle::mir::patch::MirPatch;
@@ -97,8 +97,8 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
&simplify::SimplifyCfg::new("make_shim"),
&add_call_guards::CriticalCallEdges,
&abort_unwinding_calls::AbortUnwindingCalls,
- &marker::PhaseChange(MirPhase::Runtime(RuntimePhase::Optimized)),
],
+ Some(MirPhase::Runtime(RuntimePhase::Optimized)),
);
debug!("make_shim({:?}) = {:?}", instance, result);
@@ -312,7 +312,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -
let param_env = tcx.param_env(def_id);
let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
- let is_copy = self_ty.is_copy_modulo_regions(tcx.at(builder.span), param_env);
+ let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env);
let dest = Place::return_place();
let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0)));
diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml
index 59ca04ec8..6ee5330b6 100644
--- a/compiler/rustc_monomorphize/Cargo.toml
+++ b/compiler/rustc_monomorphize/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
smallvec = { version = "1.8.1", features = [ "union", "may_dangle" ] }
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index f1a25a60d..a71218e69 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1067,7 +1067,7 @@ fn find_vtable_types_for_unsizing<'tcx>(
let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
let param_env = ty::ParamEnv::reveal_all();
let type_has_metadata = |ty: Ty<'tcx>| -> bool {
- if ty.is_sized(tcx.at(DUMMY_SP), param_env) {
+ if ty.is_sized(tcx, param_env) {
return false;
}
let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env);
@@ -1192,7 +1192,7 @@ struct RootCollector<'a, 'tcx> {
impl<'v> RootCollector<'_, 'v> {
fn process_item(&mut self, id: hir::ItemId) {
- match self.tcx.def_kind(id.def_id) {
+ match self.tcx.def_kind(id.owner_id) {
DefKind::Enum | DefKind::Struct | DefKind::Union => {
let item = self.tcx.hir().item(id);
match item.kind {
@@ -1203,12 +1203,14 @@ impl<'v> RootCollector<'_, 'v> {
if self.mode == MonoItemCollectionMode::Eager {
debug!(
"RootCollector: ADT drop-glue for {}",
- self.tcx.def_path_str(item.def_id.to_def_id())
+ self.tcx.def_path_str(item.owner_id.to_def_id())
);
- let ty =
- Instance::new(item.def_id.to_def_id(), InternalSubsts::empty())
- .ty(self.tcx, ty::ParamEnv::reveal_all());
+ let ty = Instance::new(
+ item.owner_id.to_def_id(),
+ InternalSubsts::empty(),
+ )
+ .ty(self.tcx, ty::ParamEnv::reveal_all());
visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output);
}
}
@@ -1219,23 +1221,23 @@ impl<'v> RootCollector<'_, 'v> {
DefKind::GlobalAsm => {
debug!(
"RootCollector: ItemKind::GlobalAsm({})",
- self.tcx.def_path_str(id.def_id.to_def_id())
+ self.tcx.def_path_str(id.owner_id.to_def_id())
);
self.output.push(dummy_spanned(MonoItem::GlobalAsm(id)));
}
DefKind::Static(..) => {
debug!(
"RootCollector: ItemKind::Static({})",
- self.tcx.def_path_str(id.def_id.to_def_id())
+ self.tcx.def_path_str(id.owner_id.to_def_id())
);
- self.output.push(dummy_spanned(MonoItem::Static(id.def_id.to_def_id())));
+ self.output.push(dummy_spanned(MonoItem::Static(id.owner_id.to_def_id())));
}
DefKind::Const => {
// const items only generate mono items if they are
// actually used somewhere. Just declaring them is insufficient.
// but even just declaring them must collect the items they refer to
- if let Ok(val) = self.tcx.const_eval_poly(id.def_id.to_def_id()) {
+ if let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id()) {
collect_const_value(self.tcx, val, &mut self.output);
}
}
@@ -1246,15 +1248,15 @@ impl<'v> RootCollector<'_, 'v> {
}
}
DefKind::Fn => {
- self.push_if_root(id.def_id);
+ self.push_if_root(id.owner_id.def_id);
}
_ => {}
}
}
fn process_impl_item(&mut self, id: hir::ImplItemId) {
- if matches!(self.tcx.def_kind(id.def_id), DefKind::AssocFn) {
- self.push_if_root(id.def_id);
+ if matches!(self.tcx.def_kind(id.owner_id), DefKind::AssocFn) {
+ self.push_if_root(id.owner_id.def_id);
}
}
@@ -1352,13 +1354,13 @@ fn create_mono_items_for_default_impls<'tcx>(
debug!(
"create_mono_items_for_default_impls(item={})",
- tcx.def_path_str(item.def_id.to_def_id())
+ tcx.def_path_str(item.owner_id.to_def_id())
);
- if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) {
+ if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
let param_env = ty::ParamEnv::reveal_all();
let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
- let overridden_methods = tcx.impl_item_implementor_ids(item.def_id);
+ let overridden_methods = tcx.impl_item_implementor_ids(item.owner_id);
for method in tcx.provided_trait_methods(trait_ref.def_id) {
if overridden_methods.contains_key(&method.def_id) {
continue;
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
index d5f05e790..ce097b8d8 100644
--- a/compiler/rustc_monomorphize/src/errors.rs
+++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -1,12 +1,12 @@
use std::path::PathBuf;
use rustc_errors::ErrorGuaranteed;
-use rustc_macros::{LintDiagnostic, SessionDiagnostic};
-use rustc_session::SessionDiagnostic;
+use rustc_errors::IntoDiagnostic;
+use rustc_macros::{Diagnostic, LintDiagnostic};
use rustc_span::Span;
-#[derive(SessionDiagnostic)]
-#[diag(monomorphize::recursion_limit)]
+#[derive(Diagnostic)]
+#[diag(monomorphize_recursion_limit)]
pub struct RecursionLimit {
#[primary_span]
pub span: Span,
@@ -14,26 +14,26 @@ pub struct RecursionLimit {
#[note]
pub def_span: Span,
pub def_path_str: String,
- #[note(monomorphize::written_to_path)]
+ #[note(monomorphize_written_to_path)]
pub was_written: Option<()>,
pub path: PathBuf,
}
-#[derive(SessionDiagnostic)]
-#[diag(monomorphize::type_length_limit)]
-#[help(monomorphize::consider_type_length_limit)]
+#[derive(Diagnostic)]
+#[diag(monomorphize_type_length_limit)]
+#[help(monomorphize_consider_type_length_limit)]
pub struct TypeLengthLimit {
#[primary_span]
pub span: Span,
pub shrunk: String,
- #[note(monomorphize::written_to_path)]
+ #[note(monomorphize_written_to_path)]
pub was_written: Option<()>,
pub path: PathBuf,
pub type_length: usize,
}
-#[derive(SessionDiagnostic)]
-#[diag(monomorphize::requires_lang_item)]
+#[derive(Diagnostic)]
+#[diag(monomorphize_requires_lang_item)]
pub struct RequiresLangItem {
pub lang_item: String,
}
@@ -44,13 +44,12 @@ pub struct UnusedGenericParams {
pub param_names: Vec<String>,
}
-impl SessionDiagnostic<'_> for UnusedGenericParams {
+impl IntoDiagnostic<'_> for UnusedGenericParams {
fn into_diagnostic(
self,
handler: &'_ rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
- let mut diag =
- handler.struct_err(rustc_errors::fluent::monomorphize::unused_generic_params);
+ let mut diag = handler.struct_err(rustc_errors::fluent::monomorphize_unused_generic_params);
diag.set_span(self.span);
for (span, name) in self.param_spans.into_iter().zip(self.param_names) {
// FIXME: I can figure out how to do a label with a fluent string with a fixed message,
@@ -63,7 +62,7 @@ impl SessionDiagnostic<'_> for UnusedGenericParams {
}
#[derive(LintDiagnostic)]
-#[diag(monomorphize::large_assignments)]
+#[diag(monomorphize_large_assignments)]
#[note]
pub struct LargeAssignmentsLint {
#[label]
@@ -72,12 +71,12 @@ pub struct LargeAssignmentsLint {
pub limit: u64,
}
-#[derive(SessionDiagnostic)]
-#[diag(monomorphize::unknown_partition_strategy)]
+#[derive(Diagnostic)]
+#[diag(monomorphize_unknown_partition_strategy)]
pub struct UnknownPartitionStrategy;
-#[derive(SessionDiagnostic)]
-#[diag(monomorphize::symbol_already_defined)]
+#[derive(Diagnostic)]
+#[diag(monomorphize_symbol_already_defined)]
pub struct SymbolAlreadyDefined {
#[primary_span]
pub span: Option<Span>,
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index ba6ce9fd4..42781bd25 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -1,6 +1,5 @@
#![feature(array_windows)]
#![feature(control_flow_enum)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
#![deny(rustc::untranslatable_diagnostic)]
diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs
index 15276569c..29009c480 100644
--- a/compiler/rustc_monomorphize/src/partitioning/default.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/default.rs
@@ -319,7 +319,7 @@ fn characteristic_def_id_of_mono_item<'tcx>(
Some(def_id)
}
MonoItem::Static(def_id) => Some(def_id),
- MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.to_def_id()),
+ MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.to_def_id()),
}
}
@@ -411,9 +411,9 @@ fn mono_item_visibility<'tcx>(
};
}
MonoItem::GlobalAsm(item_id) => {
- return if tcx.is_reachable_non_generic(item_id.def_id) {
+ return if tcx.is_reachable_non_generic(item_id.owner_id) {
*can_be_internalized = false;
- default_visibility(tcx, item_id.def_id.to_def_id(), false)
+ default_visibility(tcx, item_id.owner_id.to_def_id(), false)
} else {
Visibility::Hidden
};
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index 71cab0232..650076c22 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -8,6 +8,7 @@
use rustc_hir::{def::DefKind, def_id::DefId, ConstContext};
use rustc_index::bit_set::FiniteBitSet;
use rustc_middle::mir::{
+ self,
visit::{TyContext, Visitor},
Constant, ConstantKind, Local, LocalDecl, Location,
};
@@ -275,9 +276,21 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
ConstantKind::Ty(c) => {
c.visit_with(self);
}
- ConstantKind::Val(_, ty) | ConstantKind::Unevaluated(_, ty) => {
- Visitor::visit_ty(self, ty, TyContext::Location(location))
+ ConstantKind::Unevaluated(mir::UnevaluatedConst { def, substs: _, promoted }, ty) => {
+ // 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 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);
+ self.visit_body(&promoted[p]);
+ }
+ }
+
+ Visitor::visit_ty(self, ty, TyContext::Location(location));
}
+ ConstantKind::Val(_, ty) => Visitor::visit_ty(self, ty, TyContext::Location(location)),
}
}
@@ -289,7 +302,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
#[instrument(level = "debug", skip(self))]
fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- if !c.has_param_types_or_consts() {
+ if !c.has_non_region_param() {
return ControlFlow::CONTINUE;
}
@@ -299,11 +312,9 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
self.unused_parameters.clear(param.index);
ControlFlow::CONTINUE
}
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
+ ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs })
if matches!(self.tcx.def_kind(def.did), DefKind::AnonConst) =>
{
- assert_eq!(promoted, ());
-
self.visit_child_body(def.did, substs);
ControlFlow::CONTINUE
}
@@ -311,33 +322,9 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
}
}
- fn visit_mir_const(&mut self, constant: ConstantKind<'tcx>) -> ControlFlow<Self::BreakTy> {
- if !constant.has_param_types_or_consts() {
- return ControlFlow::CONTINUE;
- }
-
- match constant {
- ConstantKind::Ty(ct) => ct.visit_with(self),
- ConstantKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted: Some(p) }, _)
- // Avoid considering `T` unused when constants are of the form:
- // `<Self as Foo<T>>::foo::promoted[p]`
- if self.def_id == def.did && !self.tcx.generics_of(def.did).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);
- self.visit_body(&promoted[p]);
- ControlFlow::CONTINUE
- }
- ConstantKind::Val(..) | ConstantKind::Unevaluated(..) => {
- constant.super_visit_with(self)
- }
- }
- }
-
#[instrument(level = "debug", skip(self))]
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- if !ty.has_param_types_or_consts() {
+ if !ty.has_non_region_param() {
return ControlFlow::CONTINUE;
}
@@ -374,7 +361,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
#[instrument(level = "debug", skip(self))]
fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- if !c.has_param_types_or_consts() {
+ if !c.has_non_region_param() {
return ControlFlow::CONTINUE;
}
@@ -392,7 +379,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
#[instrument(level = "debug", skip(self))]
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- if !ty.has_param_types_or_consts() {
+ if !ty.has_non_region_param() {
return ControlFlow::CONTINUE;
}
diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml
index c6ca260e9..a5c94e164 100644
--- a/compiler/rustc_parse/Cargo.toml
+++ b/compiler/rustc_parse/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
bitflags = "1.0"
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
new file mode 100644
index 000000000..9b177c518
--- /dev/null
+++ b/compiler/rustc_parse/src/errors.rs
@@ -0,0 +1,1237 @@
+use rustc_ast::token::Token;
+use rustc_ast::Path;
+use rustc_errors::{fluent, AddToDiagnostic, Applicability, EmissionGuarantee, IntoDiagnostic};
+use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_session::errors::ExprParenthesesNeeded;
+use rustc_span::symbol::Ident;
+use rustc_span::{Span, Symbol};
+
+use crate::parser::TokenDescription;
+
+#[derive(Diagnostic)]
+#[diag(parser_maybe_report_ambiguous_plus)]
+pub(crate) struct AmbiguousPlus {
+ pub sum_ty: String,
+ #[primary_span]
+ #[suggestion(code = "({sum_ty})")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_maybe_recover_from_bad_type_plus, code = "E0178")]
+pub(crate) struct BadTypePlus {
+ pub ty: String,
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sub: BadTypePlusSub,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum BadTypePlusSub {
+ #[suggestion(
+ parser_add_paren,
+ code = "{sum_with_parens}",
+ applicability = "machine-applicable"
+ )]
+ AddParen {
+ sum_with_parens: String,
+ #[primary_span]
+ span: Span,
+ },
+ #[label(parser_forgot_paren)]
+ ForgotParen {
+ #[primary_span]
+ span: Span,
+ },
+ #[label(parser_expect_path)]
+ ExpectPath {
+ #[primary_span]
+ span: Span,
+ },
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_maybe_recover_from_bad_qpath_stage_2)]
+pub(crate) struct BadQPathStage2 {
+ #[primary_span]
+ #[suggestion(code = "", applicability = "maybe-incorrect")]
+ pub span: Span,
+ pub ty: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_incorrect_semicolon)]
+pub(crate) struct IncorrectSemicolon<'a> {
+ #[primary_span]
+ #[suggestion_short(code = "", applicability = "machine-applicable")]
+ pub span: Span,
+ #[help]
+ pub opt_help: Option<()>,
+ pub name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_incorrect_use_of_await)]
+pub(crate) struct IncorrectUseOfAwait {
+ #[primary_span]
+ #[suggestion(parentheses_suggestion, code = "", applicability = "machine-applicable")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_incorrect_use_of_await)]
+pub(crate) struct IncorrectAwait {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(postfix_suggestion, code = "{expr}.await{question_mark}")]
+ pub sugg_span: (Span, Applicability),
+ pub expr: String,
+ pub question_mark: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_in_in_typo)]
+pub(crate) struct InInTypo {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(code = "", applicability = "machine-applicable")]
+ pub sugg_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_invalid_variable_declaration)]
+pub(crate) struct InvalidVariableDeclaration {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sub: InvalidVariableDeclarationSub,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum InvalidVariableDeclarationSub {
+ #[suggestion(parser_switch_mut_let_order, applicability = "maybe-incorrect", code = "let mut")]
+ SwitchMutLetOrder(#[primary_span] Span),
+ #[suggestion(
+ parser_missing_let_before_mut,
+ applicability = "machine-applicable",
+ code = "let mut"
+ )]
+ MissingLet(#[primary_span] Span),
+ #[suggestion(parser_use_let_not_auto, applicability = "machine-applicable", code = "let")]
+ UseLetNotAuto(#[primary_span] Span),
+ #[suggestion(parser_use_let_not_var, applicability = "machine-applicable", code = "let")]
+ UseLetNotVar(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_invalid_comparison_operator)]
+pub(crate) struct InvalidComparisonOperator {
+ #[primary_span]
+ pub span: Span,
+ pub invalid: String,
+ #[subdiagnostic]
+ pub sub: InvalidComparisonOperatorSub,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum InvalidComparisonOperatorSub {
+ #[suggestion_short(use_instead, applicability = "machine-applicable", code = "{correct}")]
+ Correctable {
+ #[primary_span]
+ span: Span,
+ invalid: String,
+ correct: String,
+ },
+ #[label(spaceship_operator_invalid)]
+ Spaceship(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_invalid_logical_operator)]
+#[note]
+pub(crate) struct InvalidLogicalOperator {
+ #[primary_span]
+ pub span: Span,
+ pub incorrect: String,
+ #[subdiagnostic]
+ pub sub: InvalidLogicalOperatorSub,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum InvalidLogicalOperatorSub {
+ #[suggestion_short(
+ use_amp_amp_for_conjunction,
+ applicability = "machine-applicable",
+ code = "&&"
+ )]
+ Conjunction(#[primary_span] Span),
+ #[suggestion_short(
+ use_pipe_pipe_for_disjunction,
+ applicability = "machine-applicable",
+ code = "||"
+ )]
+ Disjunction(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_tilde_is_not_unary_operator)]
+pub(crate) struct TildeAsUnaryOperator(
+ #[primary_span]
+ #[suggestion_short(applicability = "machine-applicable", code = "!")]
+ pub Span,
+);
+
+#[derive(Diagnostic)]
+#[diag(parser_unexpected_token_after_not)]
+pub(crate) struct NotAsNegationOperator {
+ #[primary_span]
+ pub negated: Span,
+ pub negated_desc: String,
+ #[subdiagnostic]
+ pub sub: NotAsNegationOperatorSub,
+}
+
+#[derive(Subdiagnostic)]
+pub enum NotAsNegationOperatorSub {
+ #[suggestion_short(
+ parser_unexpected_token_after_not_default,
+ applicability = "machine-applicable",
+ code = "!"
+ )]
+ SuggestNotDefault(#[primary_span] Span),
+
+ #[suggestion_short(
+ parser_unexpected_token_after_not_bitwise,
+ applicability = "machine-applicable",
+ code = "!"
+ )]
+ SuggestNotBitwise(#[primary_span] Span),
+
+ #[suggestion_short(
+ parser_unexpected_token_after_not_logical,
+ applicability = "machine-applicable",
+ code = "!"
+ )]
+ SuggestNotLogical(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_malformed_loop_label)]
+pub(crate) struct MalformedLoopLabel {
+ #[primary_span]
+ #[suggestion(applicability = "machine-applicable", code = "{correct_label}")]
+ pub span: Span,
+ pub correct_label: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_lifetime_in_borrow_expression)]
+pub(crate) struct LifetimeInBorrowExpression {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(applicability = "machine-applicable", code = "")]
+ #[label]
+ pub lifetime_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_field_expression_with_generic)]
+pub(crate) struct FieldExpressionWithGeneric(#[primary_span] pub Span);
+
+#[derive(Diagnostic)]
+#[diag(parser_macro_invocation_with_qualified_path)]
+pub(crate) struct MacroInvocationWithQualifiedPath(#[primary_span] pub Span);
+
+#[derive(Diagnostic)]
+#[diag(parser_unexpected_token_after_label)]
+pub(crate) struct UnexpectedTokenAfterLabel {
+ #[primary_span]
+ #[label(parser_unexpected_token_after_label)]
+ pub span: Span,
+ #[suggestion_verbose(suggestion_remove_label, code = "")]
+ pub remove_label: Option<Span>,
+ #[subdiagnostic]
+ pub enclose_in_block: Option<UnexpectedTokenAfterLabelSugg>,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(suggestion_enclose_in_block, applicability = "machine-applicable")]
+pub(crate) struct UnexpectedTokenAfterLabelSugg {
+ #[suggestion_part(code = "{{ ")]
+ pub left: Span,
+ #[suggestion_part(code = " }}")]
+ pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_require_colon_after_labeled_expression)]
+#[note]
+pub(crate) struct RequireColonAfterLabeledExpression {
+ #[primary_span]
+ pub span: Span,
+ #[label]
+ pub label: Span,
+ #[suggestion_short(applicability = "machine-applicable", code = ": ")]
+ pub label_end: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_do_catch_syntax_removed)]
+#[note]
+pub(crate) struct DoCatchSyntaxRemoved {
+ #[primary_span]
+ #[suggestion(applicability = "machine-applicable", code = "try")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_float_literal_requires_integer_part)]
+pub(crate) struct FloatLiteralRequiresIntegerPart {
+ #[primary_span]
+ #[suggestion(applicability = "machine-applicable", code = "{correct}")]
+ pub span: Span,
+ pub correct: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_invalid_int_literal_width)]
+#[help]
+pub(crate) struct InvalidIntLiteralWidth {
+ #[primary_span]
+ pub span: Span,
+ pub width: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_invalid_num_literal_base_prefix)]
+#[note]
+pub(crate) struct InvalidNumLiteralBasePrefix {
+ #[primary_span]
+ #[suggestion(applicability = "maybe-incorrect", code = "{fixed}")]
+ pub span: Span,
+ pub fixed: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_invalid_num_literal_suffix)]
+#[help]
+pub(crate) struct InvalidNumLiteralSuffix {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub suffix: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_invalid_float_literal_width)]
+#[help]
+pub(crate) struct InvalidFloatLiteralWidth {
+ #[primary_span]
+ pub span: Span,
+ pub width: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_invalid_float_literal_suffix)]
+#[help]
+pub(crate) struct InvalidFloatLiteralSuffix {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub suffix: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_int_literal_too_large)]
+pub(crate) struct IntLiteralTooLarge {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_missing_semicolon_before_array)]
+pub(crate) struct MissingSemicolonBeforeArray {
+ #[primary_span]
+ pub open_delim: Span,
+ #[suggestion_verbose(applicability = "maybe-incorrect", code = ";")]
+ pub semicolon: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_invalid_block_macro_segment)]
+pub(crate) struct InvalidBlockMacroSegment {
+ #[primary_span]
+ pub span: Span,
+ #[label]
+ pub context: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_if_expression_missing_then_block)]
+pub(crate) struct IfExpressionMissingThenBlock {
+ #[primary_span]
+ pub if_span: Span,
+ #[subdiagnostic]
+ pub sub: IfExpressionMissingThenBlockSub,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum IfExpressionMissingThenBlockSub {
+ #[help(condition_possibly_unfinished)]
+ UnfinishedCondition(#[primary_span] Span),
+ #[help(add_then_block)]
+ AddThenBlock(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_if_expression_missing_condition)]
+pub(crate) struct IfExpressionMissingCondition {
+ #[primary_span]
+ #[label(condition_label)]
+ pub if_span: Span,
+ #[label(block_label)]
+ pub block_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_expected_expression_found_let)]
+pub(crate) struct ExpectedExpressionFoundLet {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_expected_else_block)]
+pub(crate) struct ExpectedElseBlock {
+ #[primary_span]
+ pub first_tok_span: Span,
+ pub first_tok: String,
+ #[label]
+ pub else_span: Span,
+ #[suggestion(applicability = "maybe-incorrect", code = "if ")]
+ pub condition_start: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_outer_attribute_not_allowed_on_if_else)]
+pub(crate) struct OuterAttributeNotAllowedOnIfElse {
+ #[primary_span]
+ pub last: Span,
+
+ #[label(branch_label)]
+ pub branch_span: Span,
+
+ #[label(ctx_label)]
+ pub ctx_span: Span,
+ pub ctx: String,
+
+ #[suggestion(applicability = "machine-applicable", code = "")]
+ pub attributes: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_missing_in_in_for_loop)]
+pub(crate) struct MissingInInForLoop {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sub: MissingInInForLoopSub,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum MissingInInForLoopSub {
+ // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect
+ #[suggestion_short(use_in_not_of, applicability = "maybe-incorrect", code = "in")]
+ InNotOf(#[primary_span] Span),
+ #[suggestion_short(add_in, applicability = "maybe-incorrect", code = " in ")]
+ AddIn(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_missing_comma_after_match_arm)]
+pub(crate) struct MissingCommaAfterMatchArm {
+ #[primary_span]
+ #[suggestion(applicability = "machine-applicable", code = ",")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_catch_after_try)]
+#[help]
+pub(crate) struct CatchAfterTry {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_comma_after_base_struct)]
+#[note]
+pub(crate) struct CommaAfterBaseStruct {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion_short(applicability = "machine-applicable", code = "")]
+ pub comma: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_eq_field_init)]
+pub(crate) struct EqFieldInit {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(applicability = "machine-applicable", code = ":")]
+ pub eq: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_dotdotdot)]
+pub(crate) struct DotDotDot {
+ #[primary_span]
+ #[suggestion(suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")]
+ #[suggestion(suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_left_arrow_operator)]
+pub(crate) struct LeftArrowOperator {
+ #[primary_span]
+ #[suggestion(applicability = "maybe-incorrect", code = "< -")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_remove_let)]
+pub(crate) struct RemoveLet {
+ #[primary_span]
+ #[suggestion(applicability = "machine-applicable", code = "")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_use_eq_instead)]
+pub(crate) struct UseEqInstead {
+ #[primary_span]
+ #[suggestion_short(applicability = "machine-applicable", code = "=")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_use_empty_block_not_semi)]
+pub(crate) struct UseEmptyBlockNotSemi {
+ #[primary_span]
+ #[suggestion_hidden(applicability = "machine-applicable", code = "{{}}")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_comparison_interpreted_as_generic)]
+pub(crate) struct ComparisonInterpretedAsGeneric {
+ #[primary_span]
+ #[label(label_comparison)]
+ pub comparison: Span,
+ pub r#type: Path,
+ #[label(label_args)]
+ pub args: Span,
+ #[subdiagnostic]
+ pub suggestion: ComparisonOrShiftInterpretedAsGenericSugg,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_shift_interpreted_as_generic)]
+pub(crate) struct ShiftInterpretedAsGeneric {
+ #[primary_span]
+ #[label(label_comparison)]
+ pub shift: Span,
+ pub r#type: Path,
+ #[label(label_args)]
+ pub args: Span,
+ #[subdiagnostic]
+ pub suggestion: ComparisonOrShiftInterpretedAsGenericSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+pub(crate) struct ComparisonOrShiftInterpretedAsGenericSugg {
+ #[suggestion_part(code = "(")]
+ pub left: Span,
+ #[suggestion_part(code = ")")]
+ pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_found_expr_would_be_stmt)]
+pub(crate) struct FoundExprWouldBeStmt {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub token: Token,
+ #[subdiagnostic]
+ pub suggestion: ExprParenthesesNeeded,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_leading_plus_not_supported)]
+pub(crate) struct LeadingPlusNotSupported {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[suggestion_verbose(suggestion_remove_plus, code = "", applicability = "machine-applicable")]
+ pub remove_plus: Option<Span>,
+ #[subdiagnostic]
+ pub add_parentheses: Option<ExprParenthesesNeeded>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_parentheses_with_struct_fields)]
+pub(crate) struct ParenthesesWithStructFields {
+ #[primary_span]
+ pub span: Span,
+ pub r#type: Path,
+ #[subdiagnostic]
+ pub braces_for_struct: BracesForStructLiteral,
+ #[subdiagnostic]
+ pub no_fields_for_fn: NoFieldsForFnCall,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(suggestion_braces_for_struct, applicability = "maybe-incorrect")]
+pub(crate) struct BracesForStructLiteral {
+ #[suggestion_part(code = " {{ ")]
+ pub first: Span,
+ #[suggestion_part(code = " }}")]
+ pub second: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(suggestion_no_fields_for_fn, applicability = "maybe-incorrect")]
+pub(crate) struct NoFieldsForFnCall {
+ #[suggestion_part(code = "")]
+ pub fields: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_labeled_loop_in_break)]
+pub(crate) struct LabeledLoopInBreak {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sub: WrapExpressionInParentheses,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+ parser_sugg_wrap_expression_in_parentheses,
+ applicability = "machine-applicable"
+)]
+pub(crate) struct WrapExpressionInParentheses {
+ #[suggestion_part(code = "(")]
+ pub left: Span,
+ #[suggestion_part(code = ")")]
+ pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_array_brackets_instead_of_braces)]
+pub(crate) struct ArrayBracketsInsteadOfSpaces {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sub: ArrayBracketsInsteadOfSpacesSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(suggestion, applicability = "maybe-incorrect")]
+pub(crate) struct ArrayBracketsInsteadOfSpacesSugg {
+ #[suggestion_part(code = "[")]
+ pub left: Span,
+ #[suggestion_part(code = "]")]
+ pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_match_arm_body_without_braces)]
+pub(crate) struct MatchArmBodyWithoutBraces {
+ #[primary_span]
+ #[label(label_statements)]
+ pub statements: Span,
+ #[label(label_arrow)]
+ pub arrow: Span,
+ pub num_statements: usize,
+ #[subdiagnostic]
+ pub sub: MatchArmBodyWithoutBracesSugg,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum MatchArmBodyWithoutBracesSugg {
+ #[multipart_suggestion(suggestion_add_braces, applicability = "machine-applicable")]
+ AddBraces {
+ #[suggestion_part(code = "{{ ")]
+ left: Span,
+ #[suggestion_part(code = " }}")]
+ right: Span,
+ },
+ #[suggestion(
+ suggestion_use_comma_not_semicolon,
+ code = ",",
+ applicability = "machine-applicable"
+ )]
+ UseComma {
+ #[primary_span]
+ semicolon: Span,
+ },
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_struct_literal_not_allowed_here)]
+pub(crate) struct StructLiteralNotAllowedHere {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sub: StructLiteralNotAllowedHereSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+pub(crate) struct StructLiteralNotAllowedHereSugg {
+ #[suggestion_part(code = "(")]
+ pub left: Span,
+ #[suggestion_part(code = ")")]
+ pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_invalid_interpolated_expression)]
+pub(crate) struct InvalidInterpolatedExpression {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_hexadecimal_float_literal_not_supported)]
+pub(crate) struct HexadecimalFloatLiteralNotSupported {
+ #[primary_span]
+ #[label(parser_not_supported)]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_octal_float_literal_not_supported)]
+pub(crate) struct OctalFloatLiteralNotSupported {
+ #[primary_span]
+ #[label(parser_not_supported)]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_binary_float_literal_not_supported)]
+pub(crate) struct BinaryFloatLiteralNotSupported {
+ #[primary_span]
+ #[label(parser_not_supported)]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_invalid_literal_suffix)]
+pub(crate) struct InvalidLiteralSuffix {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ // FIXME(#100717)
+ pub kind: String,
+ pub suffix: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_invalid_literal_suffix_on_tuple_index)]
+pub(crate) struct InvalidLiteralSuffixOnTupleIndex {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub suffix: Symbol,
+ #[help(tuple_exception_line_1)]
+ #[help(tuple_exception_line_2)]
+ #[help(tuple_exception_line_3)]
+ pub exception: Option<()>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_non_string_abi_literal)]
+pub(crate) struct NonStringAbiLiteral {
+ #[primary_span]
+ #[suggestion(code = "\"C\"", applicability = "maybe-incorrect")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_mismatched_closing_delimiter)]
+pub(crate) struct MismatchedClosingDelimiter {
+ #[primary_span]
+ pub spans: Vec<Span>,
+ pub delimiter: String,
+ #[label(label_unmatched)]
+ pub unmatched: Span,
+ #[label(label_opening_candidate)]
+ pub opening_candidate: Option<Span>,
+ #[label(label_unclosed)]
+ pub unclosed: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_incorrect_visibility_restriction, code = "E0704")]
+#[help]
+pub(crate) struct IncorrectVisibilityRestriction {
+ #[primary_span]
+ #[suggestion(code = "in {inner_str}", applicability = "machine-applicable")]
+ pub span: Span,
+ pub inner_str: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_assignment_else_not_allowed)]
+pub(crate) struct AssignmentElseNotAllowed {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_expected_statement_after_outer_attr)]
+pub(crate) struct ExpectedStatementAfterOuterAttr {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_doc_comment_does_not_document_anything, code = "E0585")]
+#[help]
+pub(crate) struct DocCommentDoesNotDocumentAnything {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(code = ",", applicability = "machine-applicable")]
+ pub missing_comma: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_const_let_mutually_exclusive)]
+pub(crate) struct ConstLetMutuallyExclusive {
+ #[primary_span]
+ #[suggestion(code = "const", applicability = "maybe-incorrect")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_invalid_expression_in_let_else)]
+pub(crate) struct InvalidExpressionInLetElse {
+ #[primary_span]
+ pub span: Span,
+ pub operator: &'static str,
+ #[subdiagnostic]
+ pub sugg: WrapExpressionInParentheses,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_invalid_curly_in_let_else)]
+pub(crate) struct InvalidCurlyInLetElse {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sugg: WrapExpressionInParentheses,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_compound_assignment_expression_in_let)]
+#[help]
+pub(crate) struct CompoundAssignmentExpressionInLet {
+ #[primary_span]
+ #[suggestion_short(code = "=", applicability = "maybe-incorrect")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_suffixed_literal_in_attribute)]
+#[help]
+pub(crate) struct SuffixedLiteralInAttribute {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_invalid_meta_item)]
+pub(crate) struct InvalidMetaItem {
+ #[primary_span]
+ pub span: Span,
+ pub token: Token,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion_verbose(
+ parser_sugg_escape_to_use_as_identifier,
+ applicability = "maybe-incorrect",
+ code = "r#"
+)]
+pub(crate) struct SuggEscapeToUseAsIdentifier {
+ #[primary_span]
+ pub span: Span,
+ pub ident_name: String,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(parser_sugg_remove_comma, applicability = "machine-applicable", code = "")]
+pub(crate) struct SuggRemoveComma {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum ExpectedIdentifierFound {
+ #[label(parser_expected_identifier_found_reserved_identifier)]
+ ReservedIdentifier(#[primary_span] Span),
+ #[label(parser_expected_identifier_found_keyword)]
+ Keyword(#[primary_span] Span),
+ #[label(parser_expected_identifier_found_reserved_keyword)]
+ ReservedKeyword(#[primary_span] Span),
+ #[label(parser_expected_identifier_found_doc_comment)]
+ DocComment(#[primary_span] Span),
+ #[label(parser_expected_identifier)]
+ Other(#[primary_span] Span),
+}
+
+impl ExpectedIdentifierFound {
+ pub fn new(token_descr: Option<TokenDescription>, span: Span) -> Self {
+ (match token_descr {
+ Some(TokenDescription::ReservedIdentifier) => {
+ ExpectedIdentifierFound::ReservedIdentifier
+ }
+ Some(TokenDescription::Keyword) => ExpectedIdentifierFound::Keyword,
+ Some(TokenDescription::ReservedKeyword) => ExpectedIdentifierFound::ReservedKeyword,
+ Some(TokenDescription::DocComment) => ExpectedIdentifierFound::DocComment,
+ None => ExpectedIdentifierFound::Other,
+ })(span)
+ }
+}
+
+pub(crate) struct ExpectedIdentifier {
+ pub span: Span,
+ pub token: Token,
+ pub suggest_raw: Option<SuggEscapeToUseAsIdentifier>,
+ pub suggest_remove_comma: Option<SuggRemoveComma>,
+}
+
+impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
+ fn into_diagnostic(
+ self,
+ handler: &'a rustc_errors::Handler,
+ ) -> rustc_errors::DiagnosticBuilder<'a, G> {
+ let token_descr = super::parser::TokenDescription::from_token(&self.token);
+
+ let mut diag = handler.struct_diagnostic(match token_descr {
+ Some(TokenDescription::ReservedIdentifier) => {
+ fluent::parser_expected_identifier_found_reserved_identifier_str
+ }
+ Some(TokenDescription::Keyword) => fluent::parser_expected_identifier_found_keyword_str,
+ Some(TokenDescription::ReservedKeyword) => {
+ fluent::parser_expected_identifier_found_reserved_keyword_str
+ }
+ Some(TokenDescription::DocComment) => {
+ fluent::parser_expected_identifier_found_doc_comment_str
+ }
+ None => fluent::parser_expected_identifier_found_str,
+ });
+ diag.set_span(self.span);
+ diag.set_arg("token", self.token);
+
+ if let Some(sugg) = self.suggest_raw {
+ sugg.add_to_diagnostic(&mut diag);
+ }
+
+ ExpectedIdentifierFound::new(token_descr, self.span).add_to_diagnostic(&mut diag);
+
+ if let Some(sugg) = self.suggest_remove_comma {
+ sugg.add_to_diagnostic(&mut diag);
+ }
+
+ diag
+ }
+}
+
+pub(crate) struct ExpectedSemi {
+ pub span: Span,
+ pub token: Token,
+
+ pub unexpected_token_label: Option<Span>,
+ pub sugg: ExpectedSemiSugg,
+}
+
+impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi {
+ fn into_diagnostic(
+ self,
+ handler: &'a rustc_errors::Handler,
+ ) -> rustc_errors::DiagnosticBuilder<'a, G> {
+ let token_descr = super::parser::TokenDescription::from_token(&self.token);
+
+ let mut diag = handler.struct_diagnostic(match token_descr {
+ Some(TokenDescription::ReservedIdentifier) => {
+ fluent::parser_expected_semi_found_reserved_identifier_str
+ }
+ Some(TokenDescription::Keyword) => fluent::parser_expected_semi_found_keyword_str,
+ Some(TokenDescription::ReservedKeyword) => {
+ fluent::parser_expected_semi_found_reserved_keyword_str
+ }
+ Some(TokenDescription::DocComment) => {
+ fluent::parser_expected_semi_found_doc_comment_str
+ }
+ None => fluent::parser_expected_semi_found_str,
+ });
+ diag.set_span(self.span);
+ diag.set_arg("token", self.token);
+
+ if let Some(unexpected_token_label) = self.unexpected_token_label {
+ diag.span_label(unexpected_token_label, fluent::parser_label_unexpected_token);
+ }
+
+ self.sugg.add_to_diagnostic(&mut diag);
+
+ diag
+ }
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum ExpectedSemiSugg {
+ #[suggestion(
+ parser_sugg_change_this_to_semi,
+ code = ";",
+ applicability = "machine-applicable"
+ )]
+ ChangeToSemi(#[primary_span] Span),
+ #[suggestion_short(parser_sugg_add_semi, code = ";", applicability = "machine-applicable")]
+ AddSemi(#[primary_span] Span),
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_struct_literal_body_without_path)]
+pub(crate) struct StructLiteralBodyWithoutPath {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sugg: StructLiteralBodyWithoutPathSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(suggestion, applicability = "has-placeholders")]
+pub(crate) struct StructLiteralBodyWithoutPathSugg {
+ #[suggestion_part(code = "{{ SomeStruct ")]
+ pub before: Span,
+ #[suggestion_part(code = " }}")]
+ pub after: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_unmatched_angle_brackets)]
+pub(crate) struct UnmatchedAngleBrackets {
+ #[primary_span]
+ #[suggestion(code = "", applicability = "machine-applicable")]
+ pub span: Span,
+ pub num_extra_brackets: usize,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_generic_parameters_without_angle_brackets)]
+pub(crate) struct GenericParamsWithoutAngleBrackets {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sugg: GenericParamsWithoutAngleBracketsSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+pub(crate) struct GenericParamsWithoutAngleBracketsSugg {
+ #[suggestion_part(code = "<")]
+ pub left: Span,
+ #[suggestion_part(code = ">")]
+ pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_comparison_operators_cannot_be_chained)]
+pub(crate) struct ComparisonOperatorsCannotBeChained {
+ #[primary_span]
+ pub span: Vec<Span>,
+ #[suggestion_verbose(
+ parser_sugg_turbofish_syntax,
+ code = "::",
+ applicability = "maybe-incorrect"
+ )]
+ pub suggest_turbofish: Option<Span>,
+ #[help(parser_sugg_turbofish_syntax)]
+ #[help(sugg_parentheses_for_function_args)]
+ pub help_turbofish: Option<()>,
+ #[subdiagnostic]
+ pub chaining_sugg: Option<ComparisonOperatorsCannotBeChainedSugg>,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum ComparisonOperatorsCannotBeChainedSugg {
+ #[suggestion_verbose(
+ sugg_split_comparison,
+ code = " && {middle_term}",
+ applicability = "maybe-incorrect"
+ )]
+ SplitComparison {
+ #[primary_span]
+ span: Span,
+ middle_term: String,
+ },
+ #[multipart_suggestion(sugg_parenthesize, applicability = "maybe-incorrect")]
+ Parenthesize {
+ #[suggestion_part(code = "(")]
+ left: Span,
+ #[suggestion_part(code = ")")]
+ right: Span,
+ },
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_question_mark_in_type)]
+pub(crate) struct QuestionMarkInType {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sugg: QuestionMarkInTypeSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+pub(crate) struct QuestionMarkInTypeSugg {
+ #[suggestion_part(code = "Option<")]
+ pub left: Span,
+ #[suggestion_part(code = ">")]
+ pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_unexpected_parentheses_in_for_head)]
+pub(crate) struct ParenthesesInForHead {
+ #[primary_span]
+ pub span: Vec<Span>,
+ #[subdiagnostic]
+ pub sugg: ParenthesesInForHeadSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+pub(crate) struct ParenthesesInForHeadSugg {
+ #[suggestion_part(code = "")]
+ pub left: Span,
+ #[suggestion_part(code = "")]
+ pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_doc_comment_on_param_type)]
+pub(crate) struct DocCommentOnParamType {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_attribute_on_param_type)]
+pub(crate) struct AttributeOnParamType {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_pattern_method_param_without_body, code = "E0642")]
+pub(crate) struct PatternMethodParamWithoutBody {
+ #[primary_span]
+ #[suggestion(code = "_", applicability = "machine-applicable")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_self_param_not_first)]
+pub(crate) struct SelfParamNotFirst {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_const_generic_without_braces)]
+pub(crate) struct ConstGenericWithoutBraces {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sugg: ConstGenericWithoutBracesSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+pub(crate) struct ConstGenericWithoutBracesSugg {
+ #[suggestion_part(code = "{{ ")]
+ pub left: Span,
+ #[suggestion_part(code = " }}")]
+ pub right: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_unexpected_const_param_declaration)]
+pub(crate) struct UnexpectedConstParamDeclaration {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sugg: Option<UnexpectedConstParamDeclarationSugg>,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum UnexpectedConstParamDeclarationSugg {
+ #[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+ AddParam {
+ #[suggestion_part(code = "<{snippet}>")]
+ impl_generics: Span,
+ #[suggestion_part(code = "{ident}")]
+ incorrect_decl: Span,
+ snippet: String,
+ ident: String,
+ },
+ #[multipart_suggestion(suggestion, applicability = "machine-applicable")]
+ AppendParam {
+ #[suggestion_part(code = ", {snippet}")]
+ impl_generics_end: Span,
+ #[suggestion_part(code = "{ident}")]
+ incorrect_decl: Span,
+ snippet: String,
+ ident: String,
+ },
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_unexpected_const_in_generic_param)]
+pub(crate) struct UnexpectedConstInGenericParam {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion_verbose(code = "", applicability = "maybe-incorrect")]
+ pub to_remove: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_async_move_order_incorrect)]
+pub(crate) struct AsyncMoveOrderIncorrect {
+ #[primary_span]
+ #[suggestion_verbose(code = "async move", applicability = "maybe-incorrect")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parser_double_colon_in_bound)]
+pub(crate) struct DoubleColonInBound {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(code = ": ", applicability = "machine-applicable")]
+ pub between: Span,
+}
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 63819a2f9..462bce16a 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -1,10 +1,13 @@
use crate::lexer::unicode_chars::UNICODE_ARRAY;
use rustc_ast::ast::{self, AttrStyle};
use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
-use rustc_ast::tokenstream::{Spacing, TokenStream};
+use rustc_ast::tokenstream::TokenStream;
use rustc_ast::util::unicode::contains_text_flow_control_chars;
-use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
+use rustc_errors::{
+ error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult, StashKey,
+};
use rustc_lexer::unescape::{self, Mode};
+use rustc_lexer::Cursor;
use rustc_lexer::{Base, DocStyle, RawStrError};
use rustc_session::lint::builtin::{
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
@@ -38,11 +41,20 @@ pub struct UnmatchedBrace {
pub(crate) fn parse_token_trees<'a>(
sess: &'a ParseSess,
- src: &'a str,
- start_pos: BytePos,
+ mut src: &'a str,
+ mut start_pos: BytePos,
override_span: Option<Span>,
) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
- StringReader { sess, start_pos, pos: start_pos, src, override_span }.into_token_trees()
+ // Skip `#!`, if present.
+ if let Some(shebang_len) = rustc_lexer::strip_shebang(src) {
+ src = &src[shebang_len..];
+ start_pos = start_pos + BytePos::from_usize(shebang_len);
+ }
+
+ let cursor = Cursor::new(src);
+ let string_reader =
+ StringReader { sess, start_pos, pos: start_pos, src, cursor, override_span };
+ tokentrees::TokenTreesReader::parse_all_token_trees(string_reader)
}
struct StringReader<'a> {
@@ -53,6 +65,8 @@ struct StringReader<'a> {
pos: BytePos,
/// Source text to tokenize.
src: &'a str,
+ /// Cursor for getting lexer tokens.
+ cursor: Cursor<'a>,
override_span: Option<Span>,
}
@@ -61,42 +75,198 @@ impl<'a> StringReader<'a> {
self.override_span.unwrap_or_else(|| Span::with_root_ctxt(lo, hi))
}
- /// Returns the next token, and info about preceding whitespace, if any.
- fn next_token(&mut self) -> (Spacing, Token) {
- let mut spacing = Spacing::Joint;
-
- // Skip `#!` at the start of the file
- if self.pos == self.start_pos
- && let Some(shebang_len) = rustc_lexer::strip_shebang(self.src)
- {
- self.pos = self.pos + BytePos::from_usize(shebang_len);
- spacing = Spacing::Alone;
- }
+ /// Returns the next token, paired with a bool indicating if the token was
+ /// preceded by whitespace.
+ fn next_token(&mut self) -> (Token, bool) {
+ let mut preceded_by_whitespace = false;
// Skip trivial (whitespace & comments) tokens
loop {
- let start_src_index = self.src_index(self.pos);
- let text: &str = &self.src[start_src_index..];
-
- if text.is_empty() {
- let span = self.mk_sp(self.pos, self.pos);
- return (spacing, Token::new(token::Eof, span));
- }
-
- let token = rustc_lexer::first_token(text);
-
+ let token = self.cursor.advance_token();
let start = self.pos;
self.pos = self.pos + BytePos(token.len);
debug!("next_token: {:?}({:?})", token.kind, self.str_from(start));
- match self.cook_lexer_token(token.kind, start) {
- Some(kind) => {
+ // Now "cook" the token, converting the simple `rustc_lexer::TokenKind` enum into a
+ // rich `rustc_ast::TokenKind`. This turns strings into interned symbols and runs
+ // additional validation.
+ let kind = match token.kind {
+ rustc_lexer::TokenKind::LineComment { doc_style } => {
+ // Skip non-doc comments
+ let Some(doc_style) = doc_style else {
+ self.lint_unicode_text_flow(start);
+ preceded_by_whitespace = true;
+ continue;
+ };
+
+ // Opening delimiter of the length 3 is not included into the symbol.
+ let content_start = start + BytePos(3);
+ let content = self.str_from(content_start);
+ self.cook_doc_comment(content_start, content, CommentKind::Line, doc_style)
+ }
+ rustc_lexer::TokenKind::BlockComment { doc_style, terminated } => {
+ if !terminated {
+ self.report_unterminated_block_comment(start, doc_style);
+ }
+
+ // Skip non-doc comments
+ let Some(doc_style) = doc_style else {
+ self.lint_unicode_text_flow(start);
+ preceded_by_whitespace = true;
+ continue;
+ };
+
+ // Opening delimiter of the length 3 and closing delimiter of the length 2
+ // are not included into the symbol.
+ let content_start = start + BytePos(3);
+ let content_end = self.pos - BytePos(if terminated { 2 } else { 0 });
+ let content = self.str_from_to(content_start, content_end);
+ self.cook_doc_comment(content_start, content, CommentKind::Block, doc_style)
+ }
+ rustc_lexer::TokenKind::Whitespace => {
+ preceded_by_whitespace = true;
+ continue;
+ }
+ rustc_lexer::TokenKind::Ident => {
+ let sym = nfc_normalize(self.str_from(start));
let span = self.mk_sp(start, self.pos);
- return (spacing, Token::new(kind, span));
+ self.sess.symbol_gallery.insert(sym, span);
+ token::Ident(sym, false)
}
- None => spacing = Spacing::Alone,
- }
+ rustc_lexer::TokenKind::RawIdent => {
+ let sym = nfc_normalize(self.str_from(start + BytePos(2)));
+ let span = self.mk_sp(start, self.pos);
+ self.sess.symbol_gallery.insert(sym, span);
+ if !sym.can_be_raw() {
+ self.err_span(span, &format!("`{}` cannot be a raw identifier", sym));
+ }
+ self.sess.raw_identifier_spans.borrow_mut().push(span);
+ token::Ident(sym, true)
+ }
+ rustc_lexer::TokenKind::UnknownPrefix => {
+ self.report_unknown_prefix(start);
+ let sym = nfc_normalize(self.str_from(start));
+ let span = self.mk_sp(start, self.pos);
+ self.sess.symbol_gallery.insert(sym, span);
+ token::Ident(sym, false)
+ }
+ rustc_lexer::TokenKind::InvalidIdent
+ // Do not recover an identifier with emoji if the codepoint is a confusable
+ // with a recoverable substitution token, like `➖`.
+ if !UNICODE_ARRAY
+ .iter()
+ .any(|&(c, _, _)| {
+ let sym = self.str_from(start);
+ sym.chars().count() == 1 && c == sym.chars().next().unwrap()
+ }) =>
+ {
+ let sym = nfc_normalize(self.str_from(start));
+ let span = self.mk_sp(start, self.pos);
+ self.sess.bad_unicode_identifiers.borrow_mut().entry(sym).or_default()
+ .push(span);
+ token::Ident(sym, false)
+ }
+ 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);
+ let suffix = if suffix_start < self.pos {
+ let string = self.str_from(suffix_start);
+ if string == "_" {
+ self.sess
+ .span_diagnostic
+ .struct_span_warn(
+ self.mk_sp(suffix_start, self.pos),
+ "underscore literal suffix is not allowed",
+ )
+ .warn(
+ "this was previously accepted by the compiler but is \
+ being phased out; it will become a hard error in \
+ a future release!",
+ )
+ .note(
+ "see issue #42326 \
+ <https://github.com/rust-lang/rust/issues/42326> \
+ for more information",
+ )
+ .emit();
+ None
+ } else {
+ Some(Symbol::intern(string))
+ }
+ } else {
+ None
+ };
+ token::Literal(token::Lit { kind, symbol, suffix })
+ }
+ rustc_lexer::TokenKind::Lifetime { starts_with_number } => {
+ // Include the leading `'` in the real identifier, for macro
+ // expansion purposes. See #12512 for the gory details of why
+ // this is necessary.
+ let lifetime_name = self.str_from(start);
+ if starts_with_number {
+ let span = self.mk_sp(start, self.pos);
+ let mut diag = self.sess.struct_err("lifetimes cannot start with a number");
+ diag.set_span(span);
+ diag.stash(span, StashKey::LifetimeIsChar);
+ }
+ let ident = Symbol::intern(lifetime_name);
+ token::Lifetime(ident)
+ }
+ rustc_lexer::TokenKind::Semi => token::Semi,
+ rustc_lexer::TokenKind::Comma => token::Comma,
+ rustc_lexer::TokenKind::Dot => token::Dot,
+ rustc_lexer::TokenKind::OpenParen => token::OpenDelim(Delimiter::Parenthesis),
+ rustc_lexer::TokenKind::CloseParen => token::CloseDelim(Delimiter::Parenthesis),
+ rustc_lexer::TokenKind::OpenBrace => token::OpenDelim(Delimiter::Brace),
+ rustc_lexer::TokenKind::CloseBrace => token::CloseDelim(Delimiter::Brace),
+ rustc_lexer::TokenKind::OpenBracket => token::OpenDelim(Delimiter::Bracket),
+ rustc_lexer::TokenKind::CloseBracket => token::CloseDelim(Delimiter::Bracket),
+ rustc_lexer::TokenKind::At => token::At,
+ rustc_lexer::TokenKind::Pound => token::Pound,
+ rustc_lexer::TokenKind::Tilde => token::Tilde,
+ rustc_lexer::TokenKind::Question => token::Question,
+ rustc_lexer::TokenKind::Colon => token::Colon,
+ rustc_lexer::TokenKind::Dollar => token::Dollar,
+ rustc_lexer::TokenKind::Eq => token::Eq,
+ rustc_lexer::TokenKind::Bang => token::Not,
+ rustc_lexer::TokenKind::Lt => token::Lt,
+ rustc_lexer::TokenKind::Gt => token::Gt,
+ rustc_lexer::TokenKind::Minus => token::BinOp(token::Minus),
+ rustc_lexer::TokenKind::And => token::BinOp(token::And),
+ rustc_lexer::TokenKind::Or => token::BinOp(token::Or),
+ rustc_lexer::TokenKind::Plus => token::BinOp(token::Plus),
+ rustc_lexer::TokenKind::Star => token::BinOp(token::Star),
+ rustc_lexer::TokenKind::Slash => token::BinOp(token::Slash),
+ rustc_lexer::TokenKind::Caret => token::BinOp(token::Caret),
+ rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
+
+ rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
+ let c = self.str_from(start).chars().next().unwrap();
+ let mut err =
+ self.struct_err_span_char(start, self.pos, "unknown start of token", c);
+ // FIXME: the lexer could be used to turn the ASCII version of unicode
+ // homoglyphs, instead of keeping a table in `check_for_substitution`into the
+ // token. Ideally, this should be inside `rustc_lexer`. However, we should
+ // first remove compound tokens like `<<` from `rustc_lexer`, and then add
+ // fancier error recovery to it, as there will be less overall work to do this
+ // way.
+ let token = unicode_chars::check_for_substitution(self, start, c, &mut err);
+ if c == '\x00' {
+ err.help("source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used");
+ }
+ err.emit();
+ if let Some(token) = token {
+ token
+ } else {
+ preceded_by_whitespace = true;
+ continue;
+ }
+ }
+ rustc_lexer::TokenKind::Eof => token::Eof,
+ };
+ let span = self.mk_sp(start, self.pos);
+ return (Token::new(kind, span), preceded_by_whitespace);
}
}
@@ -162,171 +332,6 @@ impl<'a> StringReader<'a> {
}
}
- /// Turns simple `rustc_lexer::TokenKind` enum into a rich
- /// `rustc_ast::TokenKind`. This turns strings into interned
- /// symbols and runs additional validation.
- fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Option<TokenKind> {
- Some(match token {
- rustc_lexer::TokenKind::LineComment { doc_style } => {
- // Skip non-doc comments
- let Some(doc_style) = doc_style else {
- self.lint_unicode_text_flow(start);
- return None;
- };
-
- // Opening delimiter of the length 3 is not included into the symbol.
- let content_start = start + BytePos(3);
- let content = self.str_from(content_start);
- self.cook_doc_comment(content_start, content, CommentKind::Line, doc_style)
- }
- rustc_lexer::TokenKind::BlockComment { doc_style, terminated } => {
- if !terminated {
- self.report_unterminated_block_comment(start, doc_style);
- }
-
- // Skip non-doc comments
- let Some(doc_style) = doc_style else {
- self.lint_unicode_text_flow(start);
- return None;
- };
-
- // Opening delimiter of the length 3 and closing delimiter of the length 2
- // are not included into the symbol.
- let content_start = start + BytePos(3);
- let content_end = self.pos - BytePos(if terminated { 2 } else { 0 });
- let content = self.str_from_to(content_start, content_end);
- self.cook_doc_comment(content_start, content, CommentKind::Block, doc_style)
- }
- rustc_lexer::TokenKind::Whitespace => return None,
- rustc_lexer::TokenKind::Ident
- | rustc_lexer::TokenKind::RawIdent
- | rustc_lexer::TokenKind::UnknownPrefix => {
- let is_raw_ident = token == rustc_lexer::TokenKind::RawIdent;
- let is_unknown_prefix = token == rustc_lexer::TokenKind::UnknownPrefix;
- let mut ident_start = start;
- if is_raw_ident {
- ident_start = ident_start + BytePos(2);
- }
- if is_unknown_prefix {
- self.report_unknown_prefix(start);
- }
- let sym = nfc_normalize(self.str_from(ident_start));
- let span = self.mk_sp(start, self.pos);
- self.sess.symbol_gallery.insert(sym, span);
- if is_raw_ident {
- if !sym.can_be_raw() {
- self.err_span(span, &format!("`{}` cannot be a raw identifier", sym));
- }
- self.sess.raw_identifier_spans.borrow_mut().push(span);
- }
- token::Ident(sym, is_raw_ident)
- }
- rustc_lexer::TokenKind::InvalidIdent
- // Do not recover an identifier with emoji if the codepoint is a confusable
- // with a recoverable substitution token, like `➖`.
- if !UNICODE_ARRAY
- .iter()
- .any(|&(c, _, _)| {
- let sym = self.str_from(start);
- sym.chars().count() == 1 && c == sym.chars().next().unwrap()
- })
- =>
- {
- let sym = nfc_normalize(self.str_from(start));
- let span = self.mk_sp(start, self.pos);
- self.sess.bad_unicode_identifiers.borrow_mut().entry(sym).or_default().push(span);
- token::Ident(sym, false)
- }
- 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);
- let suffix = if suffix_start < self.pos {
- let string = self.str_from(suffix_start);
- if string == "_" {
- self.sess
- .span_diagnostic
- .struct_span_warn(
- self.mk_sp(suffix_start, self.pos),
- "underscore literal suffix is not allowed",
- )
- .warn(
- "this was previously accepted by the compiler but is \
- being phased out; it will become a hard error in \
- a future release!",
- )
- .note(
- "see issue #42326 \
- <https://github.com/rust-lang/rust/issues/42326> \
- for more information",
- )
- .emit();
- None
- } else {
- Some(Symbol::intern(string))
- }
- } else {
- None
- };
- token::Literal(token::Lit { kind, symbol, suffix })
- }
- rustc_lexer::TokenKind::Lifetime { starts_with_number } => {
- // Include the leading `'` in the real identifier, for macro
- // expansion purposes. See #12512 for the gory details of why
- // this is necessary.
- let lifetime_name = self.str_from(start);
- if starts_with_number {
- self.err_span_(start, self.pos, "lifetimes cannot start with a number");
- }
- let ident = Symbol::intern(lifetime_name);
- token::Lifetime(ident)
- }
- rustc_lexer::TokenKind::Semi => token::Semi,
- rustc_lexer::TokenKind::Comma => token::Comma,
- rustc_lexer::TokenKind::Dot => token::Dot,
- rustc_lexer::TokenKind::OpenParen => token::OpenDelim(Delimiter::Parenthesis),
- rustc_lexer::TokenKind::CloseParen => token::CloseDelim(Delimiter::Parenthesis),
- rustc_lexer::TokenKind::OpenBrace => token::OpenDelim(Delimiter::Brace),
- rustc_lexer::TokenKind::CloseBrace => token::CloseDelim(Delimiter::Brace),
- rustc_lexer::TokenKind::OpenBracket => token::OpenDelim(Delimiter::Bracket),
- rustc_lexer::TokenKind::CloseBracket => token::CloseDelim(Delimiter::Bracket),
- rustc_lexer::TokenKind::At => token::At,
- rustc_lexer::TokenKind::Pound => token::Pound,
- rustc_lexer::TokenKind::Tilde => token::Tilde,
- rustc_lexer::TokenKind::Question => token::Question,
- rustc_lexer::TokenKind::Colon => token::Colon,
- rustc_lexer::TokenKind::Dollar => token::Dollar,
- rustc_lexer::TokenKind::Eq => token::Eq,
- rustc_lexer::TokenKind::Bang => token::Not,
- rustc_lexer::TokenKind::Lt => token::Lt,
- rustc_lexer::TokenKind::Gt => token::Gt,
- rustc_lexer::TokenKind::Minus => token::BinOp(token::Minus),
- rustc_lexer::TokenKind::And => token::BinOp(token::And),
- rustc_lexer::TokenKind::Or => token::BinOp(token::Or),
- rustc_lexer::TokenKind::Plus => token::BinOp(token::Plus),
- rustc_lexer::TokenKind::Star => token::BinOp(token::Star),
- rustc_lexer::TokenKind::Slash => token::BinOp(token::Slash),
- rustc_lexer::TokenKind::Caret => token::BinOp(token::Caret),
- rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
-
- rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
- let c = self.str_from(start).chars().next().unwrap();
- let mut err =
- self.struct_err_span_char(start, self.pos, "unknown start of token", c);
- // FIXME: the lexer could be used to turn the ASCII version of unicode homoglyphs,
- // instead of keeping a table in `check_for_substitution`into the token. Ideally,
- // this should be inside `rustc_lexer`. However, we should first remove compound
- // tokens like `<<` from `rustc_lexer`, and then add fancier error recovery to it,
- // as there will be less overall work to do this way.
- let token = unicode_chars::check_for_substitution(self, start, c, &mut err);
- if c == '\x00' {
- err.help("source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used");
- }
- err.emit();
- token?
- }
- })
- }
-
fn cook_doc_comment(
&self,
content_start: BytePos,
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index aa70912dc..b2701817d 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -1,31 +1,15 @@
use super::{StringReader, UnmatchedBrace};
-
use rustc_ast::token::{self, Delimiter, Token};
use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree};
use rustc_ast_pretty::pprust::token_to_string;
use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::PResult;
+use rustc_errors::{PErr, PResult};
use rustc_span::Span;
-impl<'a> StringReader<'a> {
- pub(super) fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
- let mut tt_reader = TokenTreesReader {
- string_reader: self,
- token: Token::dummy(),
- open_braces: Vec::new(),
- unmatched_braces: Vec::new(),
- matching_delim_spans: Vec::new(),
- last_unclosed_found_span: None,
- last_delim_empty_block_spans: FxHashMap::default(),
- matching_block_spans: Vec::new(),
- };
- let res = tt_reader.parse_all_token_trees();
- (res, tt_reader.unmatched_braces)
- }
-}
-
-struct TokenTreesReader<'a> {
+pub(super) struct TokenTreesReader<'a> {
string_reader: StringReader<'a>,
+ /// The "next" token, which has been obtained from the `StringReader` but
+ /// not yet handled by the `TokenTreesReader`.
token: Token,
/// Stack of open delimiters and their spans. Used for error message.
open_braces: Vec<(Delimiter, Span)>,
@@ -43,254 +27,232 @@ struct TokenTreesReader<'a> {
}
impl<'a> TokenTreesReader<'a> {
- // Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`.
- fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> {
- let mut buf = TokenStreamBuilder::default();
-
- self.bump();
- while self.token != token::Eof {
- buf.push(self.parse_token_tree()?);
- }
-
- Ok(buf.into_token_stream())
+ pub(super) fn parse_all_token_trees(
+ string_reader: StringReader<'a>,
+ ) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
+ let mut tt_reader = TokenTreesReader {
+ string_reader,
+ token: Token::dummy(),
+ open_braces: Vec::new(),
+ unmatched_braces: Vec::new(),
+ matching_delim_spans: Vec::new(),
+ last_unclosed_found_span: None,
+ last_delim_empty_block_spans: FxHashMap::default(),
+ matching_block_spans: Vec::new(),
+ };
+ let res = tt_reader.parse_token_trees(/* is_delimited */ false);
+ (res, tt_reader.unmatched_braces)
}
- // Parse a stream of tokens into a list of `TokenTree`s, up to a `CloseDelim`.
- fn parse_token_trees_until_close_delim(&mut self) -> TokenStream {
- let mut buf = TokenStreamBuilder::default();
+ // Parse a stream of tokens into a list of `TokenTree`s.
+ fn parse_token_trees(&mut self, is_delimited: bool) -> PResult<'a, TokenStream> {
+ self.token = self.string_reader.next_token().0;
+ let mut buf = Vec::new();
loop {
- if let token::CloseDelim(..) = self.token.kind {
- return buf.into_token_stream();
- }
-
- match self.parse_token_tree() {
- Ok(tree) => buf.push(tree),
- Err(mut e) => {
- e.emit();
- return buf.into_token_stream();
+ match self.token.kind {
+ token::OpenDelim(delim) => buf.push(self.parse_token_tree_open_delim(delim)),
+ token::CloseDelim(delim) => {
+ return if is_delimited {
+ Ok(TokenStream::new(buf))
+ } else {
+ Err(self.close_delim_err(delim))
+ };
+ }
+ token::Eof => {
+ if is_delimited {
+ self.eof_err().emit();
+ }
+ return Ok(TokenStream::new(buf));
+ }
+ _ => {
+ // Get the next normal token. This might require getting multiple adjacent
+ // single-char tokens and joining them together.
+ let (this_spacing, next_tok) = loop {
+ let (next_tok, is_next_tok_preceded_by_whitespace) =
+ self.string_reader.next_token();
+ if !is_next_tok_preceded_by_whitespace {
+ if let Some(glued) = self.token.glue(&next_tok) {
+ self.token = glued;
+ } else {
+ let this_spacing =
+ if next_tok.is_op() { Spacing::Joint } else { Spacing::Alone };
+ break (this_spacing, next_tok);
+ }
+ } else {
+ break (Spacing::Alone, next_tok);
+ }
+ };
+ let this_tok = std::mem::replace(&mut self.token, next_tok);
+ buf.push(TokenTree::Token(this_tok, this_spacing));
}
}
}
}
- fn parse_token_tree(&mut self) -> PResult<'a, TokenTree> {
- let sm = self.string_reader.sess.source_map();
-
- match self.token.kind {
- token::Eof => {
- let msg = "this file contains an unclosed delimiter";
- let mut err =
- self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg);
- for &(_, sp) in &self.open_braces {
- err.span_label(sp, "unclosed delimiter");
- self.unmatched_braces.push(UnmatchedBrace {
- expected_delim: Delimiter::Brace,
- found_delim: None,
- found_span: self.token.span,
- unclosed_span: Some(sp),
- candidate_span: None,
- });
- }
+ fn eof_err(&mut self) -> PErr<'a> {
+ let msg = "this file contains an unclosed delimiter";
+ let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg);
+ for &(_, sp) in &self.open_braces {
+ err.span_label(sp, "unclosed delimiter");
+ self.unmatched_braces.push(UnmatchedBrace {
+ expected_delim: Delimiter::Brace,
+ found_delim: None,
+ found_span: self.token.span,
+ unclosed_span: Some(sp),
+ candidate_span: None,
+ });
+ }
- if let Some((delim, _)) = self.open_braces.last() {
- if let Some((_, open_sp, close_sp)) =
- self.matching_delim_spans.iter().find(|(d, open_sp, close_sp)| {
- if let Some(close_padding) = sm.span_to_margin(*close_sp) {
- if let Some(open_padding) = sm.span_to_margin(*open_sp) {
- return delim == d && close_padding != open_padding;
- }
- }
- false
- })
- // these are in reverse order as they get inserted on close, but
- {
- // we want the last open/first close
- err.span_label(*open_sp, "this delimiter might not be properly closed...");
- err.span_label(
- *close_sp,
- "...as it matches this but it has different indentation",
- );
+ if let Some((delim, _)) = self.open_braces.last() {
+ if let Some((_, open_sp, close_sp)) =
+ self.matching_delim_spans.iter().find(|(d, open_sp, close_sp)| {
+ let sm = self.string_reader.sess.source_map();
+ if let Some(close_padding) = sm.span_to_margin(*close_sp) {
+ if let Some(open_padding) = sm.span_to_margin(*open_sp) {
+ return delim == d && close_padding != open_padding;
+ }
}
- }
- Err(err)
+ false
+ })
+ // these are in reverse order as they get inserted on close, but
+ {
+ // we want the last open/first close
+ err.span_label(*open_sp, "this delimiter might not be properly closed...");
+ err.span_label(*close_sp, "...as it matches this but it has different indentation");
}
- token::OpenDelim(delim) => {
- // The span for beginning of the delimited section
- let pre_span = self.token.span;
-
- // Parse the open delimiter.
- self.open_braces.push((delim, self.token.span));
- self.bump();
+ }
+ err
+ }
- // Parse the token trees within the delimiters.
- // We stop at any delimiter so we can try to recover if the user
- // uses an incorrect delimiter.
- let tts = self.parse_token_trees_until_close_delim();
+ fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> TokenTree {
+ // The span for beginning of the delimited section
+ let pre_span = self.token.span;
- // Expand to cover the entire delimited token tree
- let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
+ self.open_braces.push((open_delim, self.token.span));
- match self.token.kind {
- // Correct delimiter.
- token::CloseDelim(d) if d == delim => {
- let (open_brace, open_brace_span) = self.open_braces.pop().unwrap();
- let close_brace_span = self.token.span;
+ // Parse the token trees within the delimiters.
+ // We stop at any delimiter so we can try to recover if the user
+ // uses an incorrect delimiter.
+ let tts = self.parse_token_trees(/* is_delimited */ true).unwrap();
- if tts.is_empty() {
- let empty_block_span = open_brace_span.to(close_brace_span);
- if !sm.is_multiline(empty_block_span) {
- // Only track if the block is in the form of `{}`, otherwise it is
- // likely that it was written on purpose.
- self.last_delim_empty_block_spans.insert(delim, empty_block_span);
- }
- }
+ // Expand to cover the entire delimited token tree
+ let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
- //only add braces
- if let (Delimiter::Brace, Delimiter::Brace) = (open_brace, delim) {
- self.matching_block_spans.push((open_brace_span, close_brace_span));
- }
+ match self.token.kind {
+ // Correct delimiter.
+ token::CloseDelim(close_delim) if close_delim == open_delim => {
+ let (open_brace, open_brace_span) = self.open_braces.pop().unwrap();
+ let close_brace_span = self.token.span;
- if self.open_braces.is_empty() {
- // Clear up these spans to avoid suggesting them as we've found
- // properly matched delimiters so far for an entire block.
- self.matching_delim_spans.clear();
- } else {
- self.matching_delim_spans.push((
- open_brace,
- open_brace_span,
- close_brace_span,
- ));
- }
- // Parse the closing delimiter.
- self.bump();
+ if tts.is_empty() {
+ let empty_block_span = open_brace_span.to(close_brace_span);
+ let sm = self.string_reader.sess.source_map();
+ if !sm.is_multiline(empty_block_span) {
+ // Only track if the block is in the form of `{}`, otherwise it is
+ // likely that it was written on purpose.
+ self.last_delim_empty_block_spans.insert(open_delim, empty_block_span);
}
- // Incorrect delimiter.
- token::CloseDelim(other) => {
- let mut unclosed_delimiter = None;
- let mut candidate = None;
-
- if self.last_unclosed_found_span != Some(self.token.span) {
- // do not complain about the same unclosed delimiter multiple times
- self.last_unclosed_found_span = Some(self.token.span);
- // This is a conservative error: only report the last unclosed
- // delimiter. The previous unclosed delimiters could actually be
- // closed! The parser just hasn't gotten to them yet.
- if let Some(&(_, sp)) = self.open_braces.last() {
- unclosed_delimiter = Some(sp);
- };
- if let Some(current_padding) = sm.span_to_margin(self.token.span) {
- for (brace, brace_span) in &self.open_braces {
- if let Some(padding) = sm.span_to_margin(*brace_span) {
- // high likelihood of these two corresponding
- if current_padding == padding && brace == &other {
- candidate = Some(*brace_span);
- }
- }
- }
- }
- let (tok, _) = self.open_braces.pop().unwrap();
- self.unmatched_braces.push(UnmatchedBrace {
- expected_delim: tok,
- found_delim: Some(other),
- found_span: self.token.span,
- unclosed_span: unclosed_delimiter,
- candidate_span: candidate,
- });
- } else {
- self.open_braces.pop();
- }
+ }
- // If the incorrect delimiter matches an earlier opening
- // delimiter, then don't consume it (it can be used to
- // close the earlier one). Otherwise, consume it.
- // E.g., we try to recover from:
- // fn foo() {
- // bar(baz(
- // } // Incorrect delimiter but matches the earlier `{`
- if !self.open_braces.iter().any(|&(b, _)| b == other) {
- self.bump();
- }
- }
- token::Eof => {
- // Silently recover, the EOF token will be seen again
- // and an error emitted then. Thus we don't pop from
- // self.open_braces here.
- }
- _ => {}
+ //only add braces
+ if let (Delimiter::Brace, Delimiter::Brace) = (open_brace, open_delim) {
+ self.matching_block_spans.push((open_brace_span, close_brace_span));
}
- Ok(TokenTree::Delimited(delim_span, delim, tts))
+ if self.open_braces.is_empty() {
+ // Clear up these spans to avoid suggesting them as we've found
+ // properly matched delimiters so far for an entire block.
+ self.matching_delim_spans.clear();
+ } else {
+ self.matching_delim_spans.push((open_brace, open_brace_span, close_brace_span));
+ }
+ // Move past the closing delimiter.
+ self.token = self.string_reader.next_token().0;
}
- token::CloseDelim(delim) => {
- // An unexpected closing delimiter (i.e., there is no
- // 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);
+ // Incorrect delimiter.
+ token::CloseDelim(close_delim) => {
+ let mut unclosed_delimiter = None;
+ let mut candidate = None;
- // Braces are added at the end, so the last element is the biggest block
- if let Some(parent) = self.matching_block_spans.last() {
- if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) {
- // Check if the (empty block) is in the last properly closed block
- if (parent.0.to(parent.1)).contains(span) {
- err.span_label(
- span,
- "block is empty, you might have not meant to close it",
- );
- } else {
- err.span_label(parent.0, "this opening brace...");
-
- err.span_label(parent.1, "...matches this closing brace");
+ if self.last_unclosed_found_span != Some(self.token.span) {
+ // do not complain about the same unclosed delimiter multiple times
+ self.last_unclosed_found_span = Some(self.token.span);
+ // This is a conservative error: only report the last unclosed
+ // delimiter. The previous unclosed delimiters could actually be
+ // closed! The parser just hasn't gotten to them yet.
+ if let Some(&(_, sp)) = self.open_braces.last() {
+ unclosed_delimiter = Some(sp);
+ };
+ let sm = self.string_reader.sess.source_map();
+ if let Some(current_padding) = sm.span_to_margin(self.token.span) {
+ for (brace, brace_span) in &self.open_braces {
+ if let Some(padding) = sm.span_to_margin(*brace_span) {
+ // high likelihood of these two corresponding
+ if current_padding == padding && brace == &close_delim {
+ candidate = Some(*brace_span);
+ }
+ }
}
- } else {
- err.span_label(parent.0, "this opening brace...");
-
- err.span_label(parent.1, "...matches this closing brace");
}
+ let (tok, _) = self.open_braces.pop().unwrap();
+ self.unmatched_braces.push(UnmatchedBrace {
+ expected_delim: tok,
+ found_delim: Some(close_delim),
+ found_span: self.token.span,
+ unclosed_span: unclosed_delimiter,
+ candidate_span: candidate,
+ });
+ } else {
+ self.open_braces.pop();
}
- err.span_label(self.token.span, "unexpected closing delimiter");
- Err(err)
- }
- _ => {
- let tok = self.token.take();
- let mut spacing = self.bump();
- if !self.token.is_op() {
- spacing = Spacing::Alone;
+ // If the incorrect delimiter matches an earlier opening
+ // delimiter, then don't consume it (it can be used to
+ // close the earlier one). Otherwise, consume it.
+ // E.g., we try to recover from:
+ // fn foo() {
+ // bar(baz(
+ // } // Incorrect delimiter but matches the earlier `{`
+ if !self.open_braces.iter().any(|&(b, _)| b == close_delim) {
+ self.token = self.string_reader.next_token().0;
}
- Ok(TokenTree::Token(tok, spacing))
}
+ token::Eof => {
+ // Silently recover, the EOF token will be seen again
+ // and an error emitted then. Thus we don't pop from
+ // self.open_braces here.
+ }
+ _ => unreachable!(),
}
- }
- fn bump(&mut self) -> Spacing {
- let (spacing, token) = self.string_reader.next_token();
- self.token = token;
- spacing
+ TokenTree::Delimited(delim_span, open_delim, tts)
}
-}
-#[derive(Default)]
-struct TokenStreamBuilder {
- buf: Vec<TokenTree>,
-}
+ fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'a> {
+ // An unexpected closing delimiter (i.e., there is no
+ // 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);
-impl TokenStreamBuilder {
- #[inline(always)]
- fn push(&mut self, tree: TokenTree) {
- if let Some(TokenTree::Token(prev_token, Spacing::Joint)) = self.buf.last()
- && let TokenTree::Token(token, joint) = &tree
- && let Some(glued) = prev_token.glue(token)
- {
- self.buf.pop();
- self.buf.push(TokenTree::Token(glued, *joint));
- } else {
- self.buf.push(tree)
+ // Braces are added at the end, so the last element is the biggest block
+ if let Some(parent) = self.matching_block_spans.last() {
+ if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) {
+ // Check if the (empty block) is in the last properly closed block
+ if (parent.0.to(parent.1)).contains(span) {
+ err.span_label(span, "block is empty, you might have not meant to close it");
+ } else {
+ err.span_label(parent.0, "this opening brace...");
+ err.span_label(parent.1, "...matches this closing brace");
+ }
+ } else {
+ err.span_label(parent.0, "this opening brace...");
+ err.span_label(parent.1, "...matches this closing brace");
+ }
}
- }
- fn into_token_stream(self) -> TokenStream {
- TokenStream::new(self.buf)
+ err.span_label(self.token.span, "unexpected closing delimiter");
+ err
}
}
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 77c4fadab..f075de714 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -113,11 +113,26 @@ pub(crate) fn emit_unescape_error(
} else {
("", "if you meant to write a `str` literal, use double quotes")
};
-
+ let mut escaped = String::with_capacity(lit.len());
+ let mut chrs = lit.chars().peekable();
+ while let Some(first) = chrs.next() {
+ match (first, chrs.peek()) {
+ ('\\', Some('"')) => {
+ escaped.push('\\');
+ escaped.push('"');
+ chrs.next();
+ }
+ ('"', _) => {
+ escaped.push('\\');
+ escaped.push('"')
+ }
+ (c, _) => escaped.push(c),
+ };
+ }
handler.span_suggestion(
span_with_quotes,
msg,
- format!("{}\"{}\"", prefix, lit),
+ format!("{prefix}\"{escaped}\""),
Applicability::MachineApplicable,
);
}
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index a37327f42..3dcadb4c9 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -4,7 +4,6 @@
#![feature(box_patterns)]
#![feature(if_let_guard)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(never_type)]
#![feature(rustc_attrs)]
#![recursion_limit = "256"]
@@ -33,12 +32,15 @@ use parser::{emit_unclosed_delims, make_unclosed_delims_error, Parser};
pub mod lexer;
pub mod validate_attr;
+mod errors;
+
// A bunch of utility functions of the form `parse_<thing>_from_<source>`
// where <thing> includes crate, expr, item, stmt, tts, and one that
// uses a HOF to parse anything, and <source> includes file and
// `source_str`.
-/// A variant of 'panictry!' that works on a Vec<Diagnostic> instead of a single DiagnosticBuilder.
+/// A variant of 'panictry!' that works on a `Vec<Diagnostic>` instead of a single
+/// `DiagnosticBuilder`.
macro_rules! panictry_buffer {
($handler:expr, $e:expr) => {{
use rustc_errors::FatalError;
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 5fd69b15e..9e4565694 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -1,27 +1,26 @@
+use crate::errors::{InvalidMetaItem, SuffixedLiteralInAttribute};
+
use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle};
use rustc_ast as ast;
use rustc_ast::attr;
use rustc_ast::token::{self, Delimiter, Nonterminal};
-use rustc_ast_pretty::pprust;
-use rustc_errors::{error_code, Diagnostic, PResult};
+use rustc_errors::{error_code, fluent, Diagnostic, IntoDiagnostic, PResult};
use rustc_span::{sym, BytePos, Span};
use std::convert::TryInto;
// Public for rustfmt usage
#[derive(Debug)]
-pub enum InnerAttrPolicy<'a> {
+pub enum InnerAttrPolicy {
Permitted,
- Forbidden { reason: &'a str, saw_doc_comment: bool, prev_outer_attr_sp: Option<Span> },
+ Forbidden(Option<InnerAttrForbiddenReason>),
}
-const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
- permitted in this context";
-
-pub(super) const DEFAULT_INNER_ATTR_FORBIDDEN: InnerAttrPolicy<'_> = InnerAttrPolicy::Forbidden {
- reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
- saw_doc_comment: false,
- prev_outer_attr_sp: None,
-};
+#[derive(Clone, Copy, Debug)]
+pub enum InnerAttrForbiddenReason {
+ InCodeBlock,
+ AfterOuterDocComment { prev_doc_comment_span: Span },
+ AfterOuterAttribute { prev_outer_attr_sp: Span },
+}
enum OuterAttributeType {
DocComment,
@@ -40,17 +39,15 @@ impl<'a> Parser<'a> {
let prev_outer_attr_sp = outer_attrs.last().map(|attr| attr.span);
let inner_error_reason = if just_parsed_doc_comment {
- "an inner attribute is not permitted following an outer doc comment"
- } else if prev_outer_attr_sp.is_some() {
- "an inner attribute is not permitted following an outer attribute"
+ 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 {
- DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
- };
- let inner_parse_policy = InnerAttrPolicy::Forbidden {
- reason: inner_error_reason,
- saw_doc_comment: just_parsed_doc_comment,
- prev_outer_attr_sp,
+ None
};
+ let inner_parse_policy = InnerAttrPolicy::Forbidden(inner_error_reason);
just_parsed_doc_comment = false;
Some(self.parse_attribute(inner_parse_policy)?)
} else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
@@ -58,7 +55,7 @@ impl<'a> Parser<'a> {
let span = self.token.span;
let mut err = self.sess.span_diagnostic.struct_span_err_with_code(
span,
- "expected outer doc comment",
+ fluent::parser_inner_doc_comment_not_permitted,
error_code!(E0753),
);
if let Some(replacement_span) = self.annotate_following_item_if_applicable(
@@ -69,13 +66,10 @@ impl<'a> Parser<'a> {
token::CommentKind::Block => OuterAttributeType::DocBlockComment,
},
) {
- err.note(
- "inner doc comments like this (starting with `//!` or `/*!`) can \
- only appear before items",
- );
+ err.note(fluent::note);
err.span_suggestion_verbose(
replacement_span,
- "you might have meant to write a regular comment",
+ fluent::suggestion,
"",
rustc_errors::Applicability::MachineApplicable,
);
@@ -113,7 +107,7 @@ impl<'a> Parser<'a> {
// Public for rustfmt usage.
pub fn parse_attribute(
&mut self,
- inner_parse_policy: InnerAttrPolicy<'_>,
+ inner_parse_policy: InnerAttrPolicy,
) -> PResult<'a, ast::Attribute> {
debug!(
"parse_attribute: inner_parse_policy={:?} self.token={:?}",
@@ -122,35 +116,22 @@ impl<'a> Parser<'a> {
let lo = self.token.span;
// Attributes can't have attributes of their own [Editor's note: not with that attitude]
self.collect_tokens_no_attrs(|this| {
- if this.eat(&token::Pound) {
- let style = if this.eat(&token::Not) {
- ast::AttrStyle::Inner
- } else {
- ast::AttrStyle::Outer
- };
+ assert!(this.eat(&token::Pound), "parse_attribute called in non-attribute position");
- this.expect(&token::OpenDelim(Delimiter::Bracket))?;
- let item = this.parse_attr_item(false)?;
- this.expect(&token::CloseDelim(Delimiter::Bracket))?;
- let attr_sp = lo.to(this.prev_token.span);
+ let style =
+ if this.eat(&token::Not) { ast::AttrStyle::Inner } else { ast::AttrStyle::Outer };
- // Emit error if inner attribute is encountered and forbidden.
- if style == ast::AttrStyle::Inner {
- this.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy);
- }
+ this.expect(&token::OpenDelim(Delimiter::Bracket))?;
+ let item = this.parse_attr_item(false)?;
+ this.expect(&token::CloseDelim(Delimiter::Bracket))?;
+ let attr_sp = lo.to(this.prev_token.span);
- Ok(attr::mk_attr_from_item(
- &self.sess.attr_id_generator,
- item,
- None,
- style,
- attr_sp,
- ))
- } else {
- let token_str = pprust::token_to_string(&this.token);
- let msg = &format!("expected `#`, found `{token_str}`");
- Err(this.struct_span_err(this.token.span, msg))
+ // Emit error if inner attribute is encountered and forbidden.
+ if style == ast::AttrStyle::Inner {
+ this.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy);
}
+
+ Ok(attr::mk_attr_from_item(&self.sess.attr_id_generator, item, None, style, attr_sp))
})
}
@@ -190,21 +171,12 @@ impl<'a> Parser<'a> {
ForceCollect::No,
) {
Ok(Some(item)) => {
- let attr_name = match attr_type {
- OuterAttributeType::Attribute => "attribute",
- _ => "doc comment",
- };
- err.span_label(
- item.span,
- &format!("the inner {} doesn't annotate this {}", attr_name, item.kind.descr()),
- );
+ // FIXME(#100717)
+ err.set_arg("item", item.kind.descr());
+ err.span_label(item.span, fluent::label_does_not_annotate_this);
err.span_suggestion_verbose(
replacement_span,
- &format!(
- "to annotate the {}, change the {} from inner to outer style",
- item.kind.descr(),
- attr_name
- ),
+ fluent::sugg_change_inner_to_outer,
match attr_type {
OuterAttributeType::Attribute => "",
OuterAttributeType::DocBlockComment => "*",
@@ -222,22 +194,33 @@ impl<'a> Parser<'a> {
Some(replacement_span)
}
- pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy<'_>) {
- if let InnerAttrPolicy::Forbidden { reason, saw_doc_comment, prev_outer_attr_sp } = policy {
- let prev_outer_attr_note =
- if saw_doc_comment { "previous doc comment" } else { "previous outer attribute" };
-
- let mut diag = self.struct_span_err(attr_sp, reason);
-
- if let Some(prev_outer_attr_sp) = prev_outer_attr_sp {
- diag.span_label(attr_sp, "not permitted following an outer attribute")
- .span_label(prev_outer_attr_sp, prev_outer_attr_note);
- }
+ pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy) {
+ if let InnerAttrPolicy::Forbidden(reason) = policy {
+ let mut diag = match reason.as_ref().copied() {
+ Some(InnerAttrForbiddenReason::AfterOuterDocComment { prev_doc_comment_span }) => {
+ let mut diag = self.struct_span_err(
+ attr_sp,
+ fluent::parser_inner_attr_not_permitted_after_outer_doc_comment,
+ );
+ diag.span_label(attr_sp, fluent::label_attr)
+ .span_label(prev_doc_comment_span, fluent::label_prev_doc_comment);
+ diag
+ }
+ Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }) => {
+ let mut diag = self.struct_span_err(
+ attr_sp,
+ fluent::parser_inner_attr_not_permitted_after_outer_attr,
+ );
+ diag.span_label(attr_sp, fluent::label_attr)
+ .span_label(prev_outer_attr_sp, fluent::label_prev_attr);
+ diag
+ }
+ Some(InnerAttrForbiddenReason::InCodeBlock) | None => {
+ self.struct_span_err(attr_sp, fluent::parser_inner_attr_not_permitted)
+ }
+ };
- diag.note(
- "inner attributes, like `#![no_std]`, annotate the item enclosing them, and \
- are usually found at the beginning of source files",
- );
+ diag.note(fluent::parser_inner_attr_explanation);
if self
.annotate_following_item_if_applicable(
&mut diag,
@@ -246,7 +229,7 @@ impl<'a> Parser<'a> {
)
.is_some()
{
- diag.note("outer attributes, like `#[test]`, annotate the item following them");
+ diag.note(fluent::parser_outer_attr_explanation);
};
diag.emit();
}
@@ -337,12 +320,7 @@ impl<'a> Parser<'a> {
debug!("checking if {:?} is unusuffixed", lit);
if !lit.kind.is_unsuffixed() {
- self.struct_span_err(lit.span, "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.)",
- )
- .emit();
+ self.sess.emit_err(SuffixedLiteralInAttribute { span: lit.span });
}
Ok(lit)
@@ -435,9 +413,8 @@ impl<'a> Parser<'a> {
Err(err) => err.cancel(),
}
- let found = pprust::token_to_string(&self.token);
- let msg = format!("expected unsuffixed literal or identifier, found `{found}`");
- Err(self.struct_span_err(self.token.span, &msg))
+ Err(InvalidMetaItem { span: self.token.span, token: self.token.clone() }
+ .into_diagnostic(&self.sess.span_diagnostic))
}
}
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 5fdafd187..1b16ecb5e 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -32,11 +32,6 @@ pub struct AttrWrapper {
start_pos: usize,
}
-// This struct is passed around very frequently,
-// so make sure it doesn't accidentally get larger
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(AttrWrapper, 16);
-
impl AttrWrapper {
pub(super) fn new(attrs: AttrVec, start_pos: usize) -> AttrWrapper {
AttrWrapper { attrs, start_pos }
@@ -96,9 +91,6 @@ struct LazyAttrTokenStreamImpl {
replace_ranges: Box<[ReplaceRange]>,
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(LazyAttrTokenStreamImpl, 144);
-
impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
fn to_attr_token_stream(&self) -> AttrTokenStream {
// The token produced by the final call to `{,inlined_}next` was not
@@ -281,16 +273,23 @@ impl<'a> Parser<'a> {
let cursor_snapshot_next_calls = cursor_snapshot.num_next_calls;
let mut end_pos = self.token_cursor.num_next_calls;
+ let mut captured_trailing = false;
+
// Capture a trailing token if requested by the callback 'f'
match trailing {
TrailingToken::None => {}
+ TrailingToken::Gt => {
+ assert_eq!(self.token.kind, token::Gt);
+ }
TrailingToken::Semi => {
assert_eq!(self.token.kind, token::Semi);
end_pos += 1;
+ captured_trailing = true;
}
TrailingToken::MaybeComma => {
if self.token.kind == token::Comma {
end_pos += 1;
+ captured_trailing = true;
}
}
}
@@ -300,11 +299,7 @@ impl<'a> Parser<'a> {
// was not actually bumped past it. When the `LazyAttrTokenStream` gets converted
// into an `AttrTokenStream`, we will create the proper token.
if self.token_cursor.break_last_token {
- assert_eq!(
- trailing,
- TrailingToken::None,
- "Cannot set `break_last_token` and have trailing token"
- );
+ assert!(!captured_trailing, "Cannot set break_last_token and have trailing token");
end_pos += 1;
}
@@ -459,6 +454,16 @@ fn make_token_stream(
panic!("Unexpected last token {:?}", last_token)
}
}
- assert!(stack.is_empty(), "Stack should be empty: final_buf={:?} stack={:?}", final_buf, stack);
AttrTokenStream::new(final_buf.inner)
}
+
+// Some types are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+ use super::*;
+ use rustc_data_structures::static_assert_size;
+ // tidy-alphabetical-start
+ static_assert_size!(AttrWrapper, 16);
+ static_assert_size!(LazyAttrTokenStreamImpl, 144);
+ // tidy-alphabetical-end
+}
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index be524db78..309717350 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -3,6 +3,19 @@ use super::{
BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep,
TokenExpectType, TokenType,
};
+use crate::errors::{
+ AmbiguousPlus, AttributeOnParamType, BadQPathStage2, BadTypePlus, BadTypePlusSub,
+ ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
+ ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentOnParamType,
+ DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
+ GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, InInTypo,
+ IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, ParenthesesInForHead,
+ ParenthesesInForHeadSugg, PatternMethodParamWithoutBody, QuestionMarkInType,
+ QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
+ StructLiteralBodyWithoutPathSugg, SuggEscapeToUseAsIdentifier, SuggRemoveComma,
+ UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
+ UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead,
+};
use crate::lexer::UnmatchedBrace;
use rustc_ast as ast;
@@ -19,8 +32,8 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{
fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult,
};
-use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed};
-use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
+use rustc_errors::{pluralize, Diagnostic, ErrorGuaranteed, IntoDiagnostic};
+use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{Span, SpanSnippetError, DUMMY_SP};
@@ -30,9 +43,6 @@ use std::mem::take;
use crate::parser;
-const TURBOFISH_SUGGESTION_STR: &str =
- "use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments";
-
/// Creates a placeholder argument.
pub(super) fn dummy_arg(ident: Ident) -> Param {
let pat = P(Pat {
@@ -52,34 +62,6 @@ pub(super) fn dummy_arg(ident: Ident) -> Param {
}
}
-pub enum Error {
- UselessDocComment,
-}
-
-impl Error {
- fn span_err(
- self,
- sp: impl Into<MultiSpan>,
- handler: &Handler,
- ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
- match self {
- Error::UselessDocComment => {
- let mut err = struct_span_err!(
- handler,
- sp,
- E0585,
- "found a documentation comment that doesn't document anything",
- );
- err.help(
- "doc comments must come before what they document, maybe a comment was \
- intended with `//`?",
- );
- err
- }
- }
- }
-}
-
pub(super) trait RecoverQPath: Sized + 'static {
const PATH_STYLE: PathStyle = PathStyle::Expr;
fn to_ty(&self) -> Option<P<Ty>>;
@@ -242,485 +224,6 @@ impl MultiSugg {
}
}
-#[derive(SessionDiagnostic)]
-#[diag(parser::maybe_report_ambiguous_plus)]
-struct AmbiguousPlus {
- pub sum_ty: String,
- #[primary_span]
- #[suggestion(code = "({sum_ty})")]
- pub span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::maybe_recover_from_bad_type_plus, code = "E0178")]
-struct BadTypePlus {
- pub ty: String,
- #[primary_span]
- pub span: Span,
- #[subdiagnostic]
- pub sub: BadTypePlusSub,
-}
-
-#[derive(SessionSubdiagnostic)]
-pub enum BadTypePlusSub {
- #[suggestion(
- parser::add_paren,
- code = "{sum_with_parens}",
- applicability = "machine-applicable"
- )]
- AddParen {
- sum_with_parens: String,
- #[primary_span]
- span: Span,
- },
- #[label(parser::forgot_paren)]
- ForgotParen {
- #[primary_span]
- span: Span,
- },
- #[label(parser::expect_path)]
- ExpectPath {
- #[primary_span]
- span: Span,
- },
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::maybe_recover_from_bad_qpath_stage_2)]
-struct BadQPathStage2 {
- #[primary_span]
- #[suggestion(applicability = "maybe-incorrect")]
- span: Span,
- ty: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::incorrect_semicolon)]
-struct IncorrectSemicolon<'a> {
- #[primary_span]
- #[suggestion_short(applicability = "machine-applicable")]
- span: Span,
- #[help]
- opt_help: Option<()>,
- name: &'a str,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::incorrect_use_of_await)]
-struct IncorrectUseOfAwait {
- #[primary_span]
- #[suggestion(parser::parentheses_suggestion, applicability = "machine-applicable")]
- span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::incorrect_use_of_await)]
-struct IncorrectAwait {
- #[primary_span]
- span: Span,
- #[suggestion(parser::postfix_suggestion, code = "{expr}.await{question_mark}")]
- sugg_span: (Span, Applicability),
- expr: String,
- question_mark: &'static str,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::in_in_typo)]
-struct InInTypo {
- #[primary_span]
- span: Span,
- #[suggestion(applicability = "machine-applicable")]
- sugg_span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::invalid_variable_declaration)]
-pub struct InvalidVariableDeclaration {
- #[primary_span]
- pub span: Span,
- #[subdiagnostic]
- pub sub: InvalidVariableDeclarationSub,
-}
-
-#[derive(SessionSubdiagnostic)]
-pub enum InvalidVariableDeclarationSub {
- #[suggestion(
- parser::switch_mut_let_order,
- applicability = "maybe-incorrect",
- code = "let mut"
- )]
- SwitchMutLetOrder(#[primary_span] Span),
- #[suggestion(
- parser::missing_let_before_mut,
- applicability = "machine-applicable",
- code = "let mut"
- )]
- MissingLet(#[primary_span] Span),
- #[suggestion(parser::use_let_not_auto, applicability = "machine-applicable", code = "let")]
- UseLetNotAuto(#[primary_span] Span),
- #[suggestion(parser::use_let_not_var, applicability = "machine-applicable", code = "let")]
- UseLetNotVar(#[primary_span] Span),
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::invalid_comparison_operator)]
-pub(crate) struct InvalidComparisonOperator {
- #[primary_span]
- pub span: Span,
- pub invalid: String,
- #[subdiagnostic]
- pub sub: InvalidComparisonOperatorSub,
-}
-
-#[derive(SessionSubdiagnostic)]
-pub(crate) enum InvalidComparisonOperatorSub {
- #[suggestion_short(
- parser::use_instead,
- applicability = "machine-applicable",
- code = "{correct}"
- )]
- Correctable {
- #[primary_span]
- span: Span,
- invalid: String,
- correct: String,
- },
- #[label(parser::spaceship_operator_invalid)]
- Spaceship(#[primary_span] Span),
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::invalid_logical_operator)]
-#[note]
-pub(crate) struct InvalidLogicalOperator {
- #[primary_span]
- pub span: Span,
- pub incorrect: String,
- #[subdiagnostic]
- pub sub: InvalidLogicalOperatorSub,
-}
-
-#[derive(SessionSubdiagnostic)]
-pub(crate) enum InvalidLogicalOperatorSub {
- #[suggestion_short(
- parser::use_amp_amp_for_conjunction,
- applicability = "machine-applicable",
- code = "&&"
- )]
- Conjunction(#[primary_span] Span),
- #[suggestion_short(
- parser::use_pipe_pipe_for_disjunction,
- applicability = "machine-applicable",
- code = "||"
- )]
- Disjunction(#[primary_span] Span),
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::tilde_is_not_unary_operator)]
-pub(crate) struct TildeAsUnaryOperator(
- #[primary_span]
- #[suggestion_short(applicability = "machine-applicable", code = "!")]
- pub Span,
-);
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::unexpected_token_after_not)]
-pub(crate) struct NotAsNegationOperator {
- #[primary_span]
- pub negated: Span,
- pub negated_desc: String,
- #[suggestion_short(applicability = "machine-applicable", code = "!")]
- pub not: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::malformed_loop_label)]
-pub(crate) struct MalformedLoopLabel {
- #[primary_span]
- #[suggestion(applicability = "machine-applicable", code = "{correct_label}")]
- pub span: Span,
- pub correct_label: Ident,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::lifetime_in_borrow_expression)]
-pub(crate) struct LifetimeInBorrowExpression {
- #[primary_span]
- pub span: Span,
- #[suggestion(applicability = "machine-applicable", code = "")]
- #[label]
- pub lifetime_span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::field_expression_with_generic)]
-pub(crate) struct FieldExpressionWithGeneric(#[primary_span] pub Span);
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::macro_invocation_with_qualified_path)]
-pub(crate) struct MacroInvocationWithQualifiedPath(#[primary_span] pub Span);
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::unexpected_token_after_label)]
-pub(crate) struct UnexpectedTokenAfterLabel(
- #[primary_span]
- #[label(parser::unexpected_token_after_label)]
- pub Span,
-);
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::require_colon_after_labeled_expression)]
-#[note]
-pub(crate) struct RequireColonAfterLabeledExpression {
- #[primary_span]
- pub span: Span,
- #[label]
- pub label: Span,
- #[suggestion_short(applicability = "machine-applicable", code = ": ")]
- pub label_end: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::do_catch_syntax_removed)]
-#[note]
-pub(crate) struct DoCatchSyntaxRemoved {
- #[primary_span]
- #[suggestion(applicability = "machine-applicable", code = "try")]
- pub span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::float_literal_requires_integer_part)]
-pub(crate) struct FloatLiteralRequiresIntegerPart {
- #[primary_span]
- #[suggestion(applicability = "machine-applicable", code = "{correct}")]
- pub span: Span,
- pub correct: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::invalid_int_literal_width)]
-#[help]
-pub(crate) struct InvalidIntLiteralWidth {
- #[primary_span]
- pub span: Span,
- pub width: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::invalid_num_literal_base_prefix)]
-#[note]
-pub(crate) struct InvalidNumLiteralBasePrefix {
- #[primary_span]
- #[suggestion(applicability = "maybe-incorrect", code = "{fixed}")]
- pub span: Span,
- pub fixed: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::invalid_num_literal_suffix)]
-#[help]
-pub(crate) struct InvalidNumLiteralSuffix {
- #[primary_span]
- #[label]
- pub span: Span,
- pub suffix: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::invalid_float_literal_width)]
-#[help]
-pub(crate) struct InvalidFloatLiteralWidth {
- #[primary_span]
- pub span: Span,
- pub width: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::invalid_float_literal_suffix)]
-#[help]
-pub(crate) struct InvalidFloatLiteralSuffix {
- #[primary_span]
- #[label]
- pub span: Span,
- pub suffix: String,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::int_literal_too_large)]
-pub(crate) struct IntLiteralTooLarge {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::missing_semicolon_before_array)]
-pub(crate) struct MissingSemicolonBeforeArray {
- #[primary_span]
- pub open_delim: Span,
- #[suggestion_verbose(applicability = "maybe-incorrect", code = ";")]
- pub semicolon: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::invalid_block_macro_segment)]
-pub(crate) struct InvalidBlockMacroSegment {
- #[primary_span]
- pub span: Span,
- #[label]
- pub context: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::if_expression_missing_then_block)]
-pub(crate) struct IfExpressionMissingThenBlock {
- #[primary_span]
- pub if_span: Span,
- #[subdiagnostic]
- pub sub: IfExpressionMissingThenBlockSub,
-}
-
-#[derive(SessionSubdiagnostic)]
-pub(crate) enum IfExpressionMissingThenBlockSub {
- #[help(parser::condition_possibly_unfinished)]
- UnfinishedCondition(#[primary_span] Span),
- #[help(parser::add_then_block)]
- AddThenBlock(#[primary_span] Span),
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::if_expression_missing_condition)]
-pub(crate) struct IfExpressionMissingCondition {
- #[primary_span]
- #[label(parser::condition_label)]
- pub if_span: Span,
- #[label(parser::block_label)]
- pub block_span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::expected_expression_found_let)]
-pub(crate) struct ExpectedExpressionFoundLet {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::expected_else_block)]
-pub(crate) struct ExpectedElseBlock {
- #[primary_span]
- pub first_tok_span: Span,
- pub first_tok: String,
- #[label]
- pub else_span: Span,
- #[suggestion(applicability = "maybe-incorrect", code = "if ")]
- pub condition_start: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::outer_attribute_not_allowed_on_if_else)]
-pub(crate) struct OuterAttributeNotAllowedOnIfElse {
- #[primary_span]
- pub last: Span,
-
- #[label(parser::branch_label)]
- pub branch_span: Span,
-
- #[label(parser::ctx_label)]
- pub ctx_span: Span,
- pub ctx: String,
-
- #[suggestion(applicability = "machine-applicable", code = "")]
- pub attributes: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::missing_in_in_for_loop)]
-pub(crate) struct MissingInInForLoop {
- #[primary_span]
- pub span: Span,
- #[subdiagnostic]
- pub sub: MissingInInForLoopSub,
-}
-
-#[derive(SessionSubdiagnostic)]
-pub(crate) enum MissingInInForLoopSub {
- // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect
- #[suggestion_short(parser::use_in_not_of, applicability = "maybe-incorrect", code = "in")]
- InNotOf(#[primary_span] Span),
- #[suggestion_short(parser::add_in, applicability = "maybe-incorrect", code = " in ")]
- AddIn(#[primary_span] Span),
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::missing_comma_after_match_arm)]
-pub(crate) struct MissingCommaAfterMatchArm {
- #[primary_span]
- #[suggestion(applicability = "machine-applicable", code = ",")]
- pub span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::catch_after_try)]
-#[help]
-pub(crate) struct CatchAfterTry {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::comma_after_base_struct)]
-#[note]
-pub(crate) struct CommaAfterBaseStruct {
- #[primary_span]
- pub span: Span,
- #[suggestion_short(applicability = "machine-applicable", code = "")]
- pub comma: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::eq_field_init)]
-pub(crate) struct EqFieldInit {
- #[primary_span]
- pub span: Span,
- #[suggestion(applicability = "machine-applicable", code = ":")]
- pub eq: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::dotdotdot)]
-pub(crate) struct DotDotDot {
- #[primary_span]
- #[suggestion(parser::suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")]
- #[suggestion(parser::suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")]
- pub span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::left_arrow_operator)]
-pub(crate) struct LeftArrowOperator {
- #[primary_span]
- #[suggestion(applicability = "maybe-incorrect", code = "< -")]
- pub span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::remove_let)]
-pub(crate) struct RemoveLet {
- #[primary_span]
- #[suggestion(applicability = "machine-applicable", code = "")]
- pub span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(parser::use_eq_instead)]
-pub(crate) struct UseEqInstead {
- #[primary_span]
- #[suggestion_short(applicability = "machine-applicable", code = "=")]
- pub span: Span,
-}
-
// SnapshotParser is used to create a snapshot of the parser
// without causing duplicate errors being emitted when the `Parser`
// is dropped.
@@ -745,15 +248,6 @@ impl<'a> DerefMut for SnapshotParser<'a> {
impl<'a> Parser<'a> {
#[rustc_lint_diagnostics]
- pub(super) fn span_err<S: Into<MultiSpan>>(
- &self,
- sp: S,
- err: Error,
- ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
- err.span_err(sp, self.diagnostic())
- }
-
- #[rustc_lint_diagnostics]
pub fn struct_span_err<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -798,10 +292,6 @@ impl<'a> Parser<'a> {
}
pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
- let mut err = self.struct_span_err(
- self.token.span,
- &format!("expected identifier, found {}", super::token_descr(&self.token)),
- );
let valid_follow = &[
TokenKind::Eq,
TokenKind::Colon,
@@ -813,34 +303,35 @@ impl<'a> Parser<'a> {
TokenKind::CloseDelim(Delimiter::Brace),
TokenKind::CloseDelim(Delimiter::Parenthesis),
];
- match self.token.ident() {
+ let suggest_raw = match self.token.ident() {
Some((ident, false))
if ident.is_raw_guess()
&& self.look_ahead(1, |t| valid_follow.contains(&t.kind)) =>
{
- err.span_suggestion_verbose(
- ident.span.shrink_to_lo(),
- &format!("escape `{}` to use it as an identifier", ident.name),
- "r#",
- Applicability::MaybeIncorrect,
- );
+ Some(SuggEscapeToUseAsIdentifier {
+ span: ident.span.shrink_to_lo(),
+ // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`,
+ // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#`
+ ident_name: ident.name.to_string(),
+ })
}
- _ => {}
- }
- if let Some(token_descr) = super::token_descr_opt(&self.token) {
- err.span_label(self.token.span, format!("expected identifier, found {}", token_descr));
- } else {
- err.span_label(self.token.span, "expected identifier");
+ _ => None,
+ };
+
+ let suggest_remove_comma =
if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) {
- err.span_suggestion(
- self.token.span,
- "remove this comma",
- "",
- Applicability::MachineApplicable,
- );
- }
- }
- err
+ Some(SuggRemoveComma { span: self.token.span })
+ } else {
+ None
+ };
+
+ let err = ExpectedIdentifier {
+ span: self.token.span,
+ token: self.token.clone(),
+ suggest_raw,
+ suggest_remove_comma,
+ };
+ err.into_diagnostic(&self.sess.span_diagnostic)
}
pub(super) fn expected_one_of_not_found(
@@ -905,8 +396,8 @@ impl<'a> Parser<'a> {
expected.dedup();
let sm = self.sess.source_map();
- let msg = format!("expected `;`, found {}", super::token_descr(&self.token));
- let appl = Applicability::MachineApplicable;
+
+ // Special-case "expected `;`" errors
if expected.contains(&TokenType::Token(token::Semi)) {
if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP {
// Likely inside a macro, can't provide meaningful suggestions.
@@ -934,11 +425,13 @@ impl<'a> Parser<'a> {
//
// let x = 32:
// let y = 42;
+ self.sess.emit_err(ExpectedSemi {
+ span: self.token.span,
+ token: self.token.clone(),
+ unexpected_token_label: None,
+ sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span),
+ });
self.bump();
- let sp = self.prev_token.span;
- self.struct_span_err(sp, &msg)
- .span_suggestion_short(sp, "change this to `;`", ";", appl)
- .emit();
return Ok(true);
} else if self.look_ahead(0, |t| {
t == &token::CloseDelim(Delimiter::Brace)
@@ -956,11 +449,13 @@ impl<'a> Parser<'a> {
//
// let x = 32
// let y = 42;
- let sp = self.prev_token.span.shrink_to_hi();
- self.struct_span_err(sp, &msg)
- .span_label(self.token.span, "unexpected token")
- .span_suggestion_short(sp, "add `;` here", ";", appl)
- .emit();
+ let span = self.prev_token.span.shrink_to_hi();
+ self.sess.emit_err(ExpectedSemi {
+ span,
+ token: self.token.clone(),
+ unexpected_token_label: Some(self.token.span),
+ sugg: ExpectedSemiSugg::AddSemi(span),
+ });
return Ok(true);
}
}
@@ -997,6 +492,7 @@ 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);
if let TokenKind::Ident(symbol, _) = &self.prev_token.kind {
@@ -1005,7 +501,7 @@ impl<'a> Parser<'a> {
self.prev_token.span,
&format!("write `fn` instead of `{symbol}` to declare a function"),
"fn",
- appl,
+ Applicability::MachineApplicable,
);
}
}
@@ -1019,7 +515,7 @@ impl<'a> Parser<'a> {
self.prev_token.span,
"write `pub` instead of `public` to make the item public",
"pub",
- appl,
+ Applicability::MachineApplicable,
);
}
@@ -1157,19 +653,13 @@ impl<'a> Parser<'a> {
// field: value,
// } }
err.delay_as_bug();
- self.struct_span_err(
- expr.span,
- fluent::parser::struct_literal_body_without_path,
- )
- .multipart_suggestion(
- fluent::parser::suggestion,
- vec![
- (expr.span.shrink_to_lo(), "{ SomeStruct ".to_string()),
- (expr.span.shrink_to_hi(), " }".to_string()),
- ],
- Applicability::MaybeIncorrect,
- )
- .emit();
+ self.sess.emit_err(StructLiteralBodyWithoutPath {
+ span: expr.span,
+ sugg: StructLiteralBodyWithoutPathSugg {
+ before: expr.span.shrink_to_lo(),
+ after: expr.span.shrink_to_hi(),
+ },
+ });
self.restore_snapshot(snapshot);
let mut tail = self.mk_block(
vec![self.mk_stmt_err(expr.span)],
@@ -1363,18 +853,8 @@ impl<'a> Parser<'a> {
self.eat_to_tokens(end);
let span = lo.until(self.token.span);
- let total_num_of_gt = number_of_gt + number_of_shr * 2;
- self.struct_span_err(
- span,
- &format!("unmatched angle bracket{}", pluralize!(total_num_of_gt)),
- )
- .span_suggestion(
- span,
- &format!("remove extra angle bracket{}", pluralize!(total_num_of_gt)),
- "",
- Applicability::MachineApplicable,
- )
- .emit();
+ let num_extra_brackets = number_of_gt + number_of_shr * 2;
+ self.sess.emit_err(UnmatchedAngleBrackets { span, num_extra_brackets });
return true;
}
false
@@ -1403,19 +883,13 @@ impl<'a> Parser<'a> {
let args = AngleBracketedArgs { args, span }.into();
segment.args = args;
- self.struct_span_err(
+ self.sess.emit_err(GenericParamsWithoutAngleBrackets {
span,
- "generic parameters without surrounding angle brackets",
- )
- .multipart_suggestion(
- "surround the type parameters with angle brackets",
- vec![
- (span.shrink_to_lo(), "<".to_string()),
- (trailing_span, ">".to_string()),
- ],
- Applicability::MachineApplicable,
- )
- .emit();
+ sugg: GenericParamsWithoutAngleBracketsSugg {
+ left: span.shrink_to_lo(),
+ right: trailing_span,
+ },
+ });
} else {
// This doesn't look like an invalid turbofish, can't recover parse state.
self.restore_snapshot(snapshot);
@@ -1452,7 +926,7 @@ impl<'a> Parser<'a> {
if self.eat(&token::Gt) {
e.span_suggestion_verbose(
binop.span.shrink_to_lo(),
- TURBOFISH_SUGGESTION_STR,
+ fluent::parser_sugg_turbofish_syntax,
"::",
Applicability::MaybeIncorrect,
)
@@ -1484,7 +958,7 @@ impl<'a> Parser<'a> {
/// parenthesising the leftmost comparison.
fn attempt_chained_comparison_suggestion(
&mut self,
- err: &mut Diagnostic,
+ err: &mut ComparisonOperatorsCannotBeChained,
inner_op: &Expr,
outer_op: &Spanned<AssocOp>,
) -> bool /* advanced the cursor */ {
@@ -1497,16 +971,6 @@ impl<'a> Parser<'a> {
// suggestion being the only one to apply is high.
return false;
}
- let mut enclose = |left: Span, right: Span| {
- err.multipart_suggestion(
- "parenthesize the comparison",
- vec![
- (left.shrink_to_lo(), "(".to_string()),
- (right.shrink_to_hi(), ")".to_string()),
- ],
- Applicability::MaybeIncorrect,
- );
- };
return match (op.node, &outer_op.node) {
// `x == y == z`
(BinOpKind::Eq, AssocOp::Equal) |
@@ -1520,12 +984,10 @@ impl<'a> Parser<'a> {
self.span_to_snippet(e.span)
.unwrap_or_else(|_| pprust::expr_to_string(&e))
};
- err.span_suggestion_verbose(
- inner_op.span.shrink_to_hi(),
- "split the comparison into two",
- format!(" && {}", expr_to_str(&r1)),
- Applicability::MaybeIncorrect,
- );
+ err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::SplitComparison {
+ span: inner_op.span.shrink_to_hi(),
+ middle_term: expr_to_str(&r1),
+ });
false // Keep the current parse behavior, where the AST is `(x < y) < z`.
}
// `x == y < z`
@@ -1536,7 +998,10 @@ impl<'a> Parser<'a> {
Ok(r2) => {
// We are sure that outer-op-rhs could be consumed, the suggestion is
// likely correct.
- enclose(r1.span, r2.span);
+ err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::Parenthesize {
+ left: r1.span.shrink_to_lo(),
+ right: r2.span.shrink_to_hi(),
+ });
true
}
Err(expr_err) => {
@@ -1553,7 +1018,10 @@ impl<'a> Parser<'a> {
// further checks are necessary.
match self.parse_expr() {
Ok(_) => {
- enclose(l1.span, r1.span);
+ err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::Parenthesize {
+ left: l1.span.shrink_to_lo(),
+ right: r1.span.shrink_to_hi(),
+ });
true
}
Err(expr_err) => {
@@ -1602,18 +1070,11 @@ impl<'a> Parser<'a> {
match inner_op.kind {
ExprKind::Binary(op, ref l1, ref r1) if op.node.is_comparison() => {
- let mut err = self.struct_span_err(
- vec![op.span, self.prev_token.span],
- "comparison operators cannot be chained",
- );
-
- let suggest = |err: &mut Diagnostic| {
- err.span_suggestion_verbose(
- op.span.shrink_to_lo(),
- TURBOFISH_SUGGESTION_STR,
- "::",
- Applicability::MaybeIncorrect,
- );
+ let mut err = ComparisonOperatorsCannotBeChained {
+ span: vec![op.span, self.prev_token.span],
+ suggest_turbofish: None,
+ help_turbofish: None,
+ chaining_sugg: None,
};
// Include `<` to provide this recommendation even in a case like
@@ -1640,7 +1101,7 @@ impl<'a> Parser<'a> {
return if token::ModSep == self.token.kind {
// We have some certainty that this was a bad turbofish at this point.
// `foo< bar >::`
- suggest(&mut err);
+ err.suggest_turbofish = Some(op.span.shrink_to_lo());
let snapshot = self.create_snapshot_for_diagnostic();
self.bump(); // `::`
@@ -1649,7 +1110,7 @@ impl<'a> Parser<'a> {
match self.parse_expr() {
Ok(_) => {
// 99% certain that the suggestion is correct, continue parsing.
- err.emit();
+ self.sess.emit_err(err);
// FIXME: actually check that the two expressions in the binop are
// paths and resynthesize new fn call expression instead of using
// `ExprKind::Err` placeholder.
@@ -1660,18 +1121,18 @@ impl<'a> Parser<'a> {
// Not entirely sure now, but we bubble the error up with the
// suggestion.
self.restore_snapshot(snapshot);
- Err(err)
+ Err(err.into_diagnostic(&self.sess.span_diagnostic))
}
}
} else if token::OpenDelim(Delimiter::Parenthesis) == self.token.kind {
// We have high certainty that this was a bad turbofish at this point.
// `foo< bar >(`
- suggest(&mut err);
+ err.suggest_turbofish = Some(op.span.shrink_to_lo());
// Consume the fn call arguments.
match self.consume_fn_args() {
- Err(()) => Err(err),
+ Err(()) => Err(err.into_diagnostic(&self.sess.span_diagnostic)),
Ok(()) => {
- err.emit();
+ self.sess.emit_err(err);
// FIXME: actually check that the two expressions in the binop are
// paths and resynthesize new fn call expression instead of using
// `ExprKind::Err` placeholder.
@@ -1684,25 +1145,24 @@ impl<'a> Parser<'a> {
{
// All we know is that this is `foo < bar >` and *nothing* else. Try to
// be helpful, but don't attempt to recover.
- err.help(TURBOFISH_SUGGESTION_STR);
- err.help("or use `(...)` if you meant to specify fn arguments");
+ err.help_turbofish = Some(());
}
// If it looks like a genuine attempt to chain operators (as opposed to a
// misformatted turbofish, for instance), suggest a correct form.
if self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op)
{
- err.emit();
+ self.sess.emit_err(err);
mk_err_expr(self, inner_op.span.to(self.prev_token.span))
} else {
// These cases cause too many knock-down errors, bail out (#61329).
- Err(err)
+ Err(err.into_diagnostic(&self.sess.span_diagnostic))
}
};
}
let recover =
self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
- err.emit();
+ self.sess.emit_err(err);
if recover {
return mk_err_expr(self, inner_op.span.to(self.prev_token.span));
}
@@ -1743,17 +1203,13 @@ impl<'a> Parser<'a> {
pub(super) fn maybe_recover_from_question_mark(&mut self, ty: P<Ty>) -> P<Ty> {
if self.token == token::Question {
self.bump();
- self.struct_span_err(self.prev_token.span, "invalid `?` in type")
- .span_label(self.prev_token.span, "`?` is only allowed on expressions, not types")
- .multipart_suggestion(
- "if you meant to express that the type might not contain a value, use the `Option` wrapper type",
- vec![
- (ty.span.shrink_to_lo(), "Option<".to_string()),
- (self.prev_token.span, ">".to_string()),
- ],
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(QuestionMarkInType {
+ span: self.prev_token.span,
+ sugg: QuestionMarkInTypeSugg {
+ left: ty.span.shrink_to_lo(),
+ right: self.prev_token.span,
+ },
+ });
self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err)
} else {
ty
@@ -1918,9 +1374,17 @@ impl<'a> Parser<'a> {
kind: IncDecRecovery,
(pre_span, post_span): (Span, Span),
) -> MultiSugg {
+ let mut patches = Vec::new();
+
+ if !pre_span.is_empty() {
+ patches.push((pre_span, String::new()));
+ }
+
+ patches.push((post_span, format!(" {}= 1", kind.op.chr())));
+
MultiSugg {
msg: format!("use `{}= 1` instead", kind.op.chr()),
- patches: vec![(pre_span, String::new()), (post_span, format!(" {}= 1", kind.op.chr()))],
+ patches,
applicability: Applicability::MachineApplicable,
}
}
@@ -2005,7 +1469,7 @@ impl<'a> Parser<'a> {
let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) {
// Point at the end of the macro call when reaching end of macro arguments.
(token::Eof, Some(_)) => {
- let sp = self.sess.source_map().next_point(self.prev_token.span);
+ let sp = self.prev_token.span.shrink_to_hi();
(sp, sp)
}
// We don't want to point at the following span after DUMMY_SP.
@@ -2177,19 +1641,16 @@ impl<'a> Parser<'a> {
(token::CloseDelim(Delimiter::Parenthesis), Some(begin_par_sp)) => {
self.bump();
- self.struct_span_err(
- MultiSpan::from_spans(vec![begin_par_sp, self.prev_token.span]),
- "unexpected parentheses surrounding `for` loop head",
- )
- .multipart_suggestion(
- "remove parentheses in `for` loop",
- vec![(begin_par_sp, String::new()), (self.prev_token.span, String::new())],
+ self.sess.emit_err(ParenthesesInForHead {
+ span: vec![begin_par_sp, self.prev_token.span],
// With e.g. `for (x) in y)` this would replace `(x) in y)`
// with `x) in y)` which is syntactically invalid.
// However, this is prevented before we get here.
- Applicability::MachineApplicable,
- )
- .emit();
+ sugg: ParenthesesInForHeadSugg {
+ left: begin_par_sp,
+ right: self.prev_token.span,
+ },
+ });
// Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint.
pat.and_then(|pat| match pat.kind {
@@ -2408,12 +1869,7 @@ impl<'a> Parser<'a> {
pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) {
if let token::DocComment(..) = self.token.kind {
- self.struct_span_err(
- self.token.span,
- "documentation comments cannot be applied to a function parameter's type",
- )
- .span_label(self.token.span, "doc comments are not allowed here")
- .emit();
+ self.sess.emit_err(DocCommentOnParamType { span: self.token.span });
self.bump();
} else if self.token == token::Pound
&& self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Bracket))
@@ -2425,9 +1881,7 @@ impl<'a> Parser<'a> {
}
let sp = lo.to(self.token.span);
self.bump();
- self.struct_span_err(sp, "attributes cannot be applied to a function parameter's type")
- .span_label(sp, "attributes are not allowed here")
- .emit();
+ self.sess.emit_err(AttributeOnParamType { span: sp });
}
}
@@ -2548,19 +2002,7 @@ impl<'a> Parser<'a> {
self.expect(&token::Colon)?;
let ty = self.parse_ty()?;
- struct_span_err!(
- self.diagnostic(),
- pat.span,
- E0642,
- "patterns aren't allowed in methods without bodies",
- )
- .span_suggestion_short(
- pat.span,
- "give this argument a name or use an underscore to ignore it",
- "_",
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(PatternMethodParamWithoutBody { span: pat.span });
// Pretend the pattern is `_`, to avoid duplicate errors from AST validation.
let pat =
@@ -2569,11 +2011,9 @@ impl<'a> Parser<'a> {
}
pub(super) fn recover_bad_self_param(&mut self, mut param: Param) -> PResult<'a, Param> {
- let sp = param.pat.span;
+ let span = param.pat.span;
param.ty.kind = TyKind::Err;
- self.struct_span_err(sp, "unexpected `self` parameter in function")
- .span_label(sp, "must be the first parameter of an associated function")
- .emit();
+ self.sess.emit_err(SelfParamNotFirst { span });
Ok(param)
}
@@ -2607,7 +2047,7 @@ impl<'a> Parser<'a> {
pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let (span, msg) = match (&self.token.kind, self.subparser_name) {
(&token::Eof, Some(origin)) => {
- let sp = self.sess.source_map().next_point(self.prev_token.span);
+ let sp = self.prev_token.span.shrink_to_hi();
(sp, format!("expected expression, found end of {origin}"))
}
_ => (
@@ -2618,7 +2058,7 @@ impl<'a> Parser<'a> {
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) {
- self.sess.expr_parentheses_needed(&mut err, *sp);
+ err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
}
err.span_label(span, "expected expression");
err
@@ -2722,20 +2162,13 @@ impl<'a> Parser<'a> {
err
})?;
if !self.expr_is_valid_const_arg(&expr) {
- self.struct_span_err(
- expr.span,
- "expressions must be enclosed in braces to be used as const generic \
- arguments",
- )
- .multipart_suggestion(
- "enclose the `const` expression in braces",
- vec![
- (expr.span.shrink_to_lo(), "{ ".to_string()),
- (expr.span.shrink_to_hi(), " }".to_string()),
- ],
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(ConstGenericWithoutBraces {
+ span: expr.span,
+ sugg: ConstGenericWithoutBracesSugg {
+ left: expr.span.shrink_to_lo(),
+ right: expr.span.shrink_to_hi(),
+ },
+ });
}
Ok(expr)
}
@@ -2750,24 +2183,30 @@ impl<'a> Parser<'a> {
return None;
}
};
- let mut err =
- self.struct_span_err(param.span(), "unexpected `const` parameter declaration");
- err.span_label(param.span(), "expected a `const` expression, not a parameter declaration");
- if let (Some(generics), Ok(snippet)) =
- (ty_generics, self.sess.source_map().span_to_snippet(param.span()))
- {
- let (span, sugg) = match &generics.params[..] {
- [] => (generics.span, format!("<{snippet}>")),
- [.., generic] => (generic.span().shrink_to_hi(), format!(", {snippet}")),
- };
- err.multipart_suggestion(
- "`const` parameters must be declared for the `impl`",
- vec![(span, sugg), (param.span(), param.ident.to_string())],
- Applicability::MachineApplicable,
- );
- }
+
+ let ident = param.ident.to_string();
+ let sugg = match (ty_generics, self.sess.source_map().span_to_snippet(param.span())) {
+ (Some(Generics { params, span: impl_generics, .. }), Ok(snippet)) => {
+ Some(match &params[..] {
+ [] => UnexpectedConstParamDeclarationSugg::AddParam {
+ impl_generics: *impl_generics,
+ incorrect_decl: param.span(),
+ snippet,
+ ident,
+ },
+ [.., generic] => UnexpectedConstParamDeclarationSugg::AppendParam {
+ impl_generics_end: generic.span().shrink_to_hi(),
+ incorrect_decl: param.span(),
+ snippet,
+ ident,
+ },
+ })
+ }
+ _ => None,
+ };
+ self.sess.emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg });
+
let value = self.mk_expr_err(param.span());
- err.emit();
Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }))
}
@@ -2785,20 +2224,15 @@ impl<'a> Parser<'a> {
self.bump(); // `const`
// Detect and recover from the old, pre-RFC2000 syntax for const generics.
- let mut err = self
- .struct_span_err(start, "expected lifetime, type, or constant, found keyword `const`");
+ let mut err = UnexpectedConstInGenericParam { span: start, to_remove: None };
if self.check_const_arg() {
- err.span_suggestion_verbose(
- start.until(self.token.span),
- "the `const` keyword is only needed in the definition of the type",
- "",
- Applicability::MaybeIncorrect,
- );
- err.emit();
+ err.to_remove = Some(start.until(self.token.span));
+ self.sess.emit_err(err);
Ok(Some(GenericArg::Const(self.parse_const_arg()?)))
} else {
let after_kw_const = self.token.span;
- self.recover_const_arg(after_kw_const, err).map(Some)
+ self.recover_const_arg(after_kw_const, err.into_diagnostic(&self.sess.span_diagnostic))
+ .map(Some)
}
}
@@ -2806,7 +2240,7 @@ impl<'a> Parser<'a> {
///
/// When encountering code like `foo::< bar + 3 >` or `foo::< bar - baz >` we suggest
/// `foo::<{ bar + 3 }>` and `foo::<{ bar - baz }>`, respectively. We only provide a suggestion
- /// if we think that that the resulting expression would be well formed.
+ /// if we think that the resulting expression would be well formed.
pub fn recover_const_arg(
&mut self,
start: Span,
@@ -2904,24 +2338,6 @@ impl<'a> Parser<'a> {
GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
}
- /// Get the diagnostics for the cases where `move async` is found.
- ///
- /// `move_async_span` starts at the 'm' of the move keyword and ends with the 'c' of the async keyword
- pub(super) fn incorrect_move_async_order_found(
- &self,
- move_async_span: Span,
- ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
- let mut err =
- self.struct_span_err(move_async_span, "the order of `move` and `async` is incorrect");
- err.span_suggestion_verbose(
- move_async_span,
- "try switching the order",
- "async move",
- Applicability::MaybeIncorrect,
- );
- err
- }
-
/// Some special error handling for the "top-level" patterns in a match arm,
/// `for` loop, `let`, &c. (in contrast to subpatterns within such).
pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
@@ -3040,11 +2456,15 @@ impl<'a> Parser<'a> {
}
pub(crate) fn maybe_recover_unexpected_block_label(&mut self) -> bool {
- let Some(label) = self.eat_label().filter(|_| {
- self.eat(&token::Colon) && self.token.kind == token::OpenDelim(Delimiter::Brace)
- }) else {
+ // Check for `'a : {`
+ if !(self.check_lifetime()
+ && self.look_ahead(1, |tok| tok.kind == token::Colon)
+ && self.look_ahead(2, |tok| tok.kind == token::OpenDelim(Delimiter::Brace)))
+ {
return false;
- };
+ }
+ let label = self.eat_label().expect("just checked if a label exists");
+ self.bump(); // eat `:`
let span = label.ident.span.to(self.prev_token.span);
let mut err = self.struct_span_err(span, "block label not supported here");
err.span_label(span, "not supported here");
@@ -3117,17 +2537,11 @@ impl<'a> Parser<'a> {
let (a_span, b_span) = (a.span(), b.span());
let between_span = a_span.shrink_to_hi().to(b_span.shrink_to_lo());
if self.span_to_snippet(between_span).as_ref().map(|a| &a[..]) == Ok(":: ") {
- let mut err = self.struct_span_err(
- path.span.shrink_to_hi(),
- "expected `:` followed by trait or lifetime",
- );
- err.span_suggestion(
- between_span,
- "use single colon",
- ": ",
- Applicability::MachineApplicable,
- );
- return Err(err);
+ return Err(DoubleColonInBound {
+ span: path.span.shrink_to_hi(),
+ between: between_span,
+ }
+ .into_diagnostic(&self.sess.span_diagnostic));
}
}
}
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 725768c1f..a781748ef 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1,26 +1,33 @@
-use super::diagnostics::{
- CatchAfterTry, CommaAfterBaseStruct, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit,
- ExpectedElseBlock, ExpectedExpressionFoundLet, FieldExpressionWithGeneric,
- FloatLiteralRequiresIntegerPart, IfExpressionMissingCondition, IfExpressionMissingThenBlock,
- IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator,
- InvalidComparisonOperatorSub, InvalidLogicalOperator, InvalidLogicalOperatorSub,
- LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath,
- MalformedLoopLabel, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray,
- NotAsNegationOperator, OuterAttributeNotAllowedOnIfElse, RequireColonAfterLabeledExpression,
- SnapshotParser, TildeAsUnaryOperator, UnexpectedTokenAfterLabel,
-};
+use super::diagnostics::SnapshotParser;
use super::pat::{CommaRecoveryMode, RecoverColon, RecoverComma, PARAM_EXPECTED};
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{
AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions,
SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken,
};
-use crate::maybe_recover_from_interpolated_ty_qpath;
-use crate::parser::diagnostics::{
- IntLiteralTooLarge, InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth,
- InvalidIntLiteralWidth, InvalidNumLiteralBasePrefix, InvalidNumLiteralSuffix,
- MissingCommaAfterMatchArm,
+use crate::errors::{
+ ArrayBracketsInsteadOfSpaces, ArrayBracketsInsteadOfSpacesSugg, AsyncMoveOrderIncorrect,
+ BinaryFloatLiteralNotSupported, BracesForStructLiteral, CatchAfterTry, CommaAfterBaseStruct,
+ ComparisonInterpretedAsGeneric, ComparisonOrShiftInterpretedAsGenericSugg,
+ DoCatchSyntaxRemoved, DotDotDot, EqFieldInit, ExpectedElseBlock, ExpectedExpressionFoundLet,
+ FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, FoundExprWouldBeStmt,
+ HexadecimalFloatLiteralNotSupported, IfExpressionMissingCondition,
+ IfExpressionMissingThenBlock, IfExpressionMissingThenBlockSub, IntLiteralTooLarge,
+ InvalidBlockMacroSegment, InvalidComparisonOperator, InvalidComparisonOperatorSub,
+ InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth, InvalidIntLiteralWidth,
+ InvalidInterpolatedExpression, InvalidLiteralSuffix, InvalidLiteralSuffixOnTupleIndex,
+ InvalidLogicalOperator, InvalidLogicalOperatorSub, InvalidNumLiteralBasePrefix,
+ InvalidNumLiteralSuffix, LabeledLoopInBreak, LeadingPlusNotSupported, LeftArrowOperator,
+ LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, MalformedLoopLabel,
+ MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg, MissingCommaAfterMatchArm,
+ MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray, NoFieldsForFnCall,
+ NotAsNegationOperator, NotAsNegationOperatorSub, OctalFloatLiteralNotSupported,
+ OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
+ RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere,
+ StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedTokenAfterLabel,
+ UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses,
};
+use crate::maybe_recover_from_interpolated_ty_qpath;
use core::mem;
use rustc_ast::ptr::P;
@@ -35,10 +42,13 @@ use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty
use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
use rustc_ast::{ClosureBinder, StmtKind};
use rustc_ast_pretty::pprust;
-use rustc_errors::{Applicability, Diagnostic, PResult};
+use rustc_errors::{
+ Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult,
+ StashKey,
+};
+use rustc_session::errors::ExprParenthesesNeeded;
use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
use rustc_session::lint::BuiltinLintDiagnostics;
-use rustc_session::SessionDiagnostic;
use rustc_span::source_map::{self, Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, Pos};
@@ -420,13 +430,11 @@ impl<'a> Parser<'a> {
/// but the next token implies this should be parsed as an expression.
/// For example: `if let Some(x) = x { x } else { 0 } / 2`.
fn error_found_expr_would_be_stmt(&self, lhs: &Expr) {
- let mut err = self.struct_span_err(
- self.token.span,
- &format!("expected expression, found `{}`", pprust::token_to_string(&self.token),),
- );
- err.span_label(self.token.span, "expected expression");
- self.sess.expr_parentheses_needed(&mut err, lhs.span);
- err.emit();
+ self.sess.emit_err(FoundExprWouldBeStmt {
+ span: self.token.span,
+ token: self.token.clone(),
+ suggestion: ExprParenthesesNeeded::surrounding(lhs.span),
+ });
}
/// Possibly translate the current token to an associative operator.
@@ -577,21 +585,16 @@ impl<'a> Parser<'a> {
make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo))
}
token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
- let mut err = this.struct_span_err(lo, "leading `+` is not supported");
- err.span_label(lo, "unexpected `+`");
+ let mut err =
+ LeadingPlusNotSupported { span: lo, remove_plus: None, add_parentheses: None };
// a block on the LHS might have been intended to be an expression instead
if let Some(sp) = this.sess.ambiguous_block_expr_parse.borrow().get(&lo) {
- this.sess.expr_parentheses_needed(&mut err, *sp);
+ err.add_parentheses = Some(ExprParenthesesNeeded::surrounding(*sp));
} else {
- err.span_suggestion_verbose(
- lo,
- "try removing the `+`",
- "",
- Applicability::MachineApplicable,
- );
+ err.remove_plus = Some(lo);
}
- err.emit();
+ this.sess.emit_err(err);
this.bump();
this.parse_prefix_expr(None)
@@ -660,12 +663,23 @@ impl<'a> Parser<'a> {
fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
// Emit the error...
let negated_token = self.look_ahead(1, |t| t.clone());
+
+ let sub_diag = if negated_token.is_numeric_lit() {
+ NotAsNegationOperatorSub::SuggestNotBitwise
+ } else if negated_token.is_bool_lit() {
+ NotAsNegationOperatorSub::SuggestNotLogical
+ } else {
+ NotAsNegationOperatorSub::SuggestNotDefault
+ };
+
self.sess.emit_err(NotAsNegationOperator {
negated: negated_token.span,
negated_desc: super::token_descr(&negated_token),
// Span the `not` plus trailing whitespace to avoid
// trailing whitespace after the `!` in our suggestion
- not: self.sess.source_map().span_until_non_whitespace(lo.to(negated_token.span)),
+ sub: sub_diag(
+ self.sess.source_map().span_until_non_whitespace(lo.to(negated_token.span)),
+ ),
});
// ...and recover!
@@ -743,9 +757,34 @@ impl<'a> Parser<'a> {
match self.parse_path(PathStyle::Expr) {
Ok(path) => {
- let (op_noun, op_verb) = match self.token.kind {
- token::Lt => ("comparison", "comparing"),
- token::BinOp(token::Shl) => ("shift", "shifting"),
+ let span_after_type = parser_snapshot_after_type.token.span;
+ let expr = mk_expr(
+ self,
+ lhs,
+ self.mk_ty(path.span, TyKind::Path(None, path.clone())),
+ );
+
+ let args_span = self.look_ahead(1, |t| t.span).to(span_after_type);
+ let suggestion = ComparisonOrShiftInterpretedAsGenericSugg {
+ left: expr.span.shrink_to_lo(),
+ right: expr.span.shrink_to_hi(),
+ };
+
+ match self.token.kind {
+ token::Lt => self.sess.emit_err(ComparisonInterpretedAsGeneric {
+ comparison: self.token.span,
+ r#type: path,
+ args: args_span,
+ suggestion,
+ }),
+ token::BinOp(token::Shl) => {
+ self.sess.emit_err(ShiftInterpretedAsGeneric {
+ shift: self.token.span,
+ r#type: path,
+ args: args_span,
+ suggestion,
+ })
+ }
_ => {
// We can end up here even without `<` being the next token, for
// example because `parse_ty_no_plus` returns `Err` on keywords,
@@ -759,33 +798,7 @@ impl<'a> Parser<'a> {
// Successfully parsed the type path leaving a `<` yet to parse.
type_err.cancel();
- // Report non-fatal diagnostics, keep `x as usize` as an expression
- // in AST and continue parsing.
- let msg = format!(
- "`<` is interpreted as a start of generic arguments for `{}`, not a {}",
- pprust::path_to_string(&path),
- op_noun,
- );
- let span_after_type = parser_snapshot_after_type.token.span;
- let expr =
- mk_expr(self, lhs, self.mk_ty(path.span, TyKind::Path(None, path)));
-
- self.struct_span_err(self.token.span, &msg)
- .span_label(
- self.look_ahead(1, |t| t.span).to(span_after_type),
- "interpreted as generic arguments",
- )
- .span_label(self.token.span, format!("not interpreted as {op_noun}"))
- .multipart_suggestion(
- &format!("try {op_verb} the cast value"),
- vec![
- (expr.span.shrink_to_lo(), "(".to_string()),
- (expr.span.shrink_to_hi(), ")".to_string()),
- ],
- Applicability::MachineApplicable,
- )
- .emit();
-
+ // Keep `x as usize` as an expression in AST and continue parsing.
expr
}
Err(path_err) => {
@@ -832,7 +845,7 @@ impl<'a> Parser<'a> {
ExprKind::Index(_, _) => "indexing",
ExprKind::Try(_) => "`?`",
ExprKind::Field(_, _) => "a field access",
- ExprKind::MethodCall(_, _, _) => "a method call",
+ ExprKind::MethodCall(_, _, _, _) => "a method call",
ExprKind::Call(_, _) => "a function call",
ExprKind::Await(_) => "`.await`",
ExprKind::Err => return Ok(with_postfix),
@@ -1146,7 +1159,9 @@ impl<'a> Parser<'a> {
}
let span = self.prev_token.span;
let field = ExprKind::Field(base, Ident::new(field, span));
- self.expect_no_suffix(span, "a tuple index", suffix);
+ if let Some(suffix) = suffix {
+ self.expect_no_tuple_index_suffix(span, suffix);
+ }
self.mk_expr(lo.to(span), field)
}
@@ -1184,9 +1199,8 @@ impl<'a> Parser<'a> {
) -> Option<P<Expr>> {
match (seq.as_mut(), snapshot) {
(Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {
- let name = pprust::path_to_string(&path);
snapshot.bump(); // `(`
- match snapshot.parse_struct_fields(path, false, Delimiter::Parenthesis) {
+ match snapshot.parse_struct_fields(path.clone(), false, Delimiter::Parenthesis) {
Ok((fields, ..))
if snapshot.eat(&token::CloseDelim(Delimiter::Parenthesis)) =>
{
@@ -1196,29 +1210,25 @@ impl<'a> Parser<'a> {
let close_paren = self.prev_token.span;
let span = lo.to(self.prev_token.span);
if !fields.is_empty() {
- let replacement_err = self.struct_span_err(
+ let mut replacement_err = ParenthesesWithStructFields {
span,
- "invalid `struct` delimiters or `fn` call arguments",
- );
- mem::replace(err, replacement_err).cancel();
-
- err.multipart_suggestion(
- &format!("if `{name}` is a struct, use braces as delimiters"),
- vec![
- (open_paren, " { ".to_string()),
- (close_paren, " }".to_string()),
- ],
- Applicability::MaybeIncorrect,
- );
- err.multipart_suggestion(
- &format!("if `{name}` is a function, use the arguments directly"),
- fields
- .into_iter()
- .map(|field| (field.span.until(field.expr.span), String::new()))
- .collect(),
- Applicability::MaybeIncorrect,
- );
- err.emit();
+ r#type: path,
+ braces_for_struct: BracesForStructLiteral {
+ first: open_paren,
+ second: close_paren,
+ },
+ no_fields_for_fn: NoFieldsForFnCall {
+ fields: fields
+ .into_iter()
+ .map(|field| field.span.until(field.expr.span))
+ .collect(),
+ },
+ }
+ .into_diagnostic(&self.sess.span_diagnostic);
+ replacement_err.emit();
+
+ let old_err = mem::replace(err, replacement_err);
+ old_err.cancel();
} else {
err.emit();
}
@@ -1259,12 +1269,10 @@ impl<'a> Parser<'a> {
if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
// Method call `expr.f()`
- let mut args = self.parse_paren_expr_seq()?;
- args.insert(0, self_arg);
-
+ let args = self.parse_paren_expr_seq()?;
let fn_span = fn_span_lo.to(self.prev_token.span);
let span = lo.to(self.prev_token.span);
- Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args, fn_span)))
+ Ok(self.mk_expr(span, ExprKind::MethodCall(segment, self_arg, args, fn_span)))
} else {
// Field access `expr.f`
if let Some(args) = segment.args {
@@ -1304,7 +1312,7 @@ impl<'a> Parser<'a> {
// If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }`
// then suggest parens around the lhs.
if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&lo) {
- self.sess.expr_parentheses_needed(&mut err, *sp);
+ err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
}
err
})
@@ -1507,11 +1515,11 @@ impl<'a> Parser<'a> {
/// Parse `'label: $expr`. The label is already parsed.
fn parse_labeled_expr(
&mut self,
- label: Label,
+ label_: Label,
mut consume_colon: bool,
) -> PResult<'a, P<Expr>> {
- let lo = label.ident.span;
- let label = Some(label);
+ let lo = label_.ident.span;
+ let label = Some(label_);
let ate_colon = self.eat(&token::Colon);
let expr = if self.eat_keyword(kw::While) {
self.parse_while_expr(label, lo)
@@ -1524,18 +1532,35 @@ impl<'a> Parser<'a> {
{
self.parse_block_expr(label, lo, BlockCheckMode::Default)
} else if !ate_colon
+ && (matches!(self.token.kind, token::CloseDelim(_) | token::Comma)
+ || self.token.is_op())
+ {
+ let lit = self.recover_unclosed_char(label_.ident, |self_| {
+ self_.sess.create_err(UnexpectedTokenAfterLabel {
+ span: self_.token.span,
+ remove_label: None,
+ enclose_in_block: None,
+ })
+ });
+ consume_colon = false;
+ Ok(self.mk_expr(lo, ExprKind::Lit(lit)))
+ } else if !ate_colon
&& (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
{
// We're probably inside of a `Path<'a>` that needs a turbofish
- self.sess.emit_err(UnexpectedTokenAfterLabel(self.token.span));
+ self.sess.emit_err(UnexpectedTokenAfterLabel {
+ span: self.token.span,
+ remove_label: None,
+ enclose_in_block: None,
+ });
consume_colon = false;
Ok(self.mk_expr_err(lo))
} else {
- // FIXME: use UnexpectedTokenAfterLabel, needs multipart suggestions
- let msg = "expected `while`, `for`, `loop` or `{` after a label";
-
- let mut err = self.struct_span_err(self.token.span, msg);
- err.span_label(self.token.span, msg);
+ let mut err = UnexpectedTokenAfterLabel {
+ span: self.token.span,
+ remove_label: None,
+ enclose_in_block: None,
+ };
// Continue as an expression in an effort to recover on `'label: non_block_expr`.
let expr = self.parse_expr().map(|expr| {
@@ -1562,28 +1587,15 @@ impl<'a> Parser<'a> {
// If there are no breaks that may use this label, suggest removing the label and
// recover to the unmodified expression.
if !found_labeled_breaks {
- let msg = "consider removing the label";
- err.span_suggestion_verbose(
- lo.until(span),
- msg,
- "",
- Applicability::MachineApplicable,
- );
+ err.remove_label = Some(lo.until(span));
return expr;
}
- let sugg_msg = "consider enclosing expression in a block";
- let suggestions = vec![
- (span.shrink_to_lo(), "{ ".to_owned()),
- (span.shrink_to_hi(), " }".to_owned()),
- ];
-
- err.multipart_suggestion_verbose(
- sugg_msg,
- suggestions,
- Applicability::MachineApplicable,
- );
+ err.enclose_in_block = Some(UnexpectedTokenAfterLabelSugg {
+ left: span.shrink_to_lo(),
+ right: span.shrink_to_hi(),
+ });
// Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to suppress future errors about `break 'label`.
let stmt = self.mk_stmt(span, StmtKind::Expr(expr));
@@ -1591,7 +1603,7 @@ impl<'a> Parser<'a> {
self.mk_expr(span, ExprKind::Block(blk, label))
});
- err.emit();
+ self.sess.emit_err(err);
expr
}?;
@@ -1606,6 +1618,39 @@ impl<'a> Parser<'a> {
Ok(expr)
}
+ /// Emit an error when a char is parsed as a lifetime because of a missing quote
+ pub(super) fn recover_unclosed_char(
+ &mut self,
+ lifetime: Ident,
+ err: impl FnOnce(&mut Self) -> DiagnosticBuilder<'a, ErrorGuaranteed>,
+ ) -> ast::Lit {
+ if let Some(mut diag) =
+ self.sess.span_diagnostic.steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar)
+ {
+ diag.span_suggestion_verbose(
+ lifetime.span.shrink_to_hi(),
+ "add `'` to close the char literal",
+ "'",
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ } else {
+ err(self)
+ .span_suggestion_verbose(
+ lifetime.span.shrink_to_hi(),
+ "add `'` to close the char literal",
+ "'",
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ }
+ ast::Lit {
+ token_lit: token::Lit::new(token::LitKind::Char, lifetime.name, None),
+ kind: ast::LitKind::Char(lifetime.name.as_str().chars().next().unwrap_or('_')),
+ span: lifetime.span,
+ }
+ }
+
/// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
fn recover_do_catch(&mut self) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
@@ -1662,19 +1707,13 @@ impl<'a> Parser<'a> {
// The value expression can be a labeled loop, see issue #86948, e.g.:
// `loop { break 'label: loop { break 'label 42; }; }`
let lexpr = self.parse_labeled_expr(label.take().unwrap(), true)?;
- self.struct_span_err(
- lexpr.span,
- "parentheses are required around this expression to avoid confusion with a labeled break expression",
- )
- .multipart_suggestion(
- "wrap the expression in parentheses",
- vec![
- (lexpr.span.shrink_to_lo(), "(".to_string()),
- (lexpr.span.shrink_to_hi(), ")".to_string()),
- ],
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(LabeledLoopInBreak {
+ span: lexpr.span,
+ sub: WrapExpressionInParentheses {
+ left: lexpr.span.shrink_to_lo(),
+ right: lexpr.span.shrink_to_hi(),
+ },
+ });
Some(lexpr)
} else if self.token != token::OpenDelim(Delimiter::Brace)
|| !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
@@ -1737,7 +1776,7 @@ impl<'a> Parser<'a> {
}
pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> {
- self.parse_opt_lit().ok_or_else(|| {
+ self.parse_opt_lit().ok_or(()).or_else(|()| {
if let token::Interpolated(inner) = &self.token.kind {
let expr = match inner.as_ref() {
token::NtExpr(expr) => Some(expr),
@@ -1746,16 +1785,25 @@ impl<'a> Parser<'a> {
};
if let Some(expr) = expr {
if matches!(expr.kind, ExprKind::Err) {
- let mut err = self
- .diagnostic()
- .struct_span_err(self.token.span, "invalid interpolated expression");
+ let mut err = InvalidInterpolatedExpression { span: self.token.span }
+ .into_diagnostic(&self.sess.span_diagnostic);
err.downgrade_to_delayed_bug();
- return err;
+ return Err(err);
}
}
}
- let msg = format!("unexpected token: {}", super::token_descr(&self.token));
- self.struct_span_err(self.token.span, &msg)
+ let token = self.token.clone();
+ let err = |self_: &mut Self| {
+ let msg = format!("unexpected token: {}", super::token_descr(&token));
+ 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() {
+ let lt = self.expect_lifetime();
+ Ok(self.recover_unclosed_char(lt.ident, err))
+ } else {
+ Err(err(self))
+ }
})
}
@@ -1780,7 +1828,10 @@ impl<'a> Parser<'a> {
});
if let Some(token) = &recovered {
self.bump();
- self.error_float_lits_must_have_int_part(&token);
+ self.sess.emit_err(FloatLiteralRequiresIntegerPart {
+ span: token.span,
+ correct: pprust::token_to_string(token).into_owned(),
+ });
}
}
@@ -1808,13 +1859,6 @@ impl<'a> Parser<'a> {
}
}
- fn error_float_lits_must_have_int_part(&self, token: &Token) {
- self.sess.emit_err(FloatLiteralRequiresIntegerPart {
- span: token.span,
- correct: pprust::token_to_string(token).into_owned(),
- });
- }
-
fn report_lit_error(&self, 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 {
@@ -1843,11 +1887,13 @@ impl<'a> Parser<'a> {
// by lexer, so here we don't report it the second time.
LitError::LexerError => {}
LitError::InvalidSuffix => {
- self.expect_no_suffix(
- span,
- &format!("{} {} literal", kind.article(), kind.descr()),
- suffix,
- );
+ if let Some(suffix) = suffix {
+ self.sess.emit_err(InvalidLiteralSuffix {
+ span,
+ kind: format!("{}", kind.descr()),
+ suffix,
+ });
+ }
}
LitError::InvalidIntSuffix => {
let suf = suffix.expect("suffix error with no suffix");
@@ -1873,15 +1919,12 @@ impl<'a> Parser<'a> {
}
}
LitError::NonDecimalFloat(base) => {
- let descr = match base {
- 16 => "hexadecimal",
- 8 => "octal",
- 2 => "binary",
+ match base {
+ 16 => self.sess.emit_err(HexadecimalFloatLiteralNotSupported { span }),
+ 8 => self.sess.emit_err(OctalFloatLiteralNotSupported { span }),
+ 2 => self.sess.emit_err(BinaryFloatLiteralNotSupported { span }),
_ => unreachable!(),
};
- self.struct_span_err(span, &format!("{descr} float literal is not supported"))
- .span_label(span, "not supported")
- .emit();
}
LitError::IntTooLarge => {
self.sess.emit_err(IntLiteralTooLarge { span });
@@ -1889,38 +1932,17 @@ impl<'a> Parser<'a> {
}
}
- pub(super) fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<Symbol>) {
- if let Some(suf) = suffix {
- let mut err = if kind == "a tuple index"
- && [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suf)
- {
- // #59553: warn instead of reject out of hand to allow the fix to percolate
- // through the ecosystem when people fix their macros
- let mut err = self
- .sess
- .span_diagnostic
- .struct_span_warn(sp, &format!("suffixes on {kind} are invalid"));
- err.note(&format!(
- "`{}` is *temporarily* accepted on tuple index fields as it was \
- incorrectly accepted on stable for a few releases",
- suf,
- ));
- err.help(
- "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",
- );
- err.note(
- "see issue #60210 <https://github.com/rust-lang/rust/issues/60210> \
- for more information",
- );
- err
- } else {
- self.struct_span_err(sp, &format!("suffixes on {kind} are invalid"))
- .forget_guarantee()
- };
- err.span_label(sp, format!("invalid suffix `{suf}`"));
- err.emit();
+ pub(super) fn expect_no_tuple_index_suffix(&self, span: Span, suffix: Symbol) {
+ if [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suffix) {
+ // #59553: warn instead of reject out of hand to allow the fix to percolate
+ // through the ecosystem when people fix their macros
+ self.sess.emit_warning(InvalidLiteralSuffixOnTupleIndex {
+ span,
+ suffix,
+ exception: Some(()),
+ });
+ } else {
+ self.sess.emit_err(InvalidLiteralSuffixOnTupleIndex { span, suffix, exception: None });
}
}
@@ -1954,14 +1976,13 @@ impl<'a> Parser<'a> {
let mut snapshot = self.create_snapshot_for_diagnostic();
match snapshot.parse_array_or_repeat_expr(Delimiter::Brace) {
Ok(arr) => {
- let hi = snapshot.prev_token.span;
- self.struct_span_err(arr.span, "this is a block expression, not an array")
- .multipart_suggestion(
- "to make an array, use square brackets instead of curly braces",
- vec![(lo, "[".to_owned()), (hi, "]".to_owned())],
- Applicability::MaybeIncorrect,
- )
- .emit();
+ self.sess.emit_err(ArrayBracketsInsteadOfSpaces {
+ span: arr.span,
+ sub: ArrayBracketsInsteadOfSpacesSugg {
+ left: lo,
+ right: snapshot.prev_token.span,
+ },
+ });
self.restore_snapshot(snapshot);
Some(self.mk_expr_err(arr.span))
@@ -2088,6 +2109,12 @@ impl<'a> Parser<'a> {
if self.token.kind == TokenKind::Semi
&& matches!(self.token_cursor.frame.delim_sp, Some((Delimiter::Parenthesis, _)))
+ // HACK: This is needed so we can detect whether we're inside a macro,
+ // where regular assumptions about what tokens can follow other tokens
+ // don't necessarily apply.
+ && self.may_recover()
+ // FIXME(Nilstrieb): Remove this check once `may_recover` actually stops recovery
+ && self.subparser_name.is_none()
{
// It is likely that the closure body is a block but where the
// braces have been removed. We will recover and eat the next
@@ -2124,7 +2151,8 @@ impl<'a> Parser<'a> {
// Check for `move async` and recover
if self.check_keyword(kw::Async) {
let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
- Err(self.incorrect_move_async_order_found(move_async_span))
+ Err(AsyncMoveOrderIncorrect { span: move_async_span }
+ .into_diagnostic(&self.sess.span_diagnostic))
} else {
Ok(CaptureBy::Value)
}
@@ -2208,7 +2236,7 @@ impl<'a> Parser<'a> {
},
ExprKind::Block(_, None) => {
self.sess.emit_err(IfExpressionMissingCondition {
- if_span: self.sess.source_map().next_point(lo),
+ if_span: lo.shrink_to_hi(),
block_span: self.sess.source_map().start_point(cond_span),
});
std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi()))
@@ -2505,39 +2533,22 @@ impl<'a> Parser<'a> {
self.bump(); // `;`
let mut stmts =
vec![self.mk_stmt(first_expr.span, ast::StmtKind::Expr(first_expr.clone()))];
- let err = |this: &mut Parser<'_>, stmts: Vec<ast::Stmt>| {
+ let err = |this: &Parser<'_>, stmts: Vec<ast::Stmt>| {
let span = stmts[0].span.to(stmts[stmts.len() - 1].span);
- let mut err = this.struct_span_err(span, "`match` arm body without braces");
- let (these, s, are) =
- if stmts.len() > 1 { ("these", "s", "are") } else { ("this", "", "is") };
- err.span_label(
- span,
- &format!(
- "{these} statement{s} {are} not surrounded by a body",
- these = these,
- s = s,
- are = are
- ),
- );
- err.span_label(arrow_span, "while parsing the `match` arm starting here");
- if stmts.len() > 1 {
- err.multipart_suggestion(
- &format!("surround the statement{s} with a body"),
- vec![
- (span.shrink_to_lo(), "{ ".to_string()),
- (span.shrink_to_hi(), " }".to_string()),
- ],
- Applicability::MachineApplicable,
- );
- } else {
- err.span_suggestion(
- semi_sp,
- "use a comma to end a `match` arm expression",
- ",",
- Applicability::MachineApplicable,
- );
- }
- err.emit();
+
+ this.sess.emit_err(MatchArmBodyWithoutBraces {
+ statements: span,
+ arrow: arrow_span,
+ num_statements: stmts.len(),
+ sub: if stmts.len() > 1 {
+ MatchArmBodyWithoutBracesSugg::AddBraces {
+ left: span.shrink_to_lo(),
+ right: span.shrink_to_hi(),
+ }
+ } else {
+ MatchArmBodyWithoutBracesSugg::UseComma { semicolon: semi_sp }
+ },
+ });
this.mk_expr_err(span)
};
// We might have either a `,` -> `;` typo, or a block without braces. We need
@@ -2826,23 +2837,19 @@ impl<'a> Parser<'a> {
let expr = self.parse_struct_expr(qself.cloned(), path.clone(), true);
if let (Ok(expr), false) = (&expr, struct_allowed) {
// This is a struct literal, but we don't can't accept them here.
- self.error_struct_lit_not_allowed_here(path.span, expr.span);
+ self.sess.emit_err(StructLiteralNotAllowedHere {
+ span: expr.span,
+ sub: StructLiteralNotAllowedHereSugg {
+ left: path.span.shrink_to_lo(),
+ right: expr.span.shrink_to_hi(),
+ },
+ });
}
return Some(expr);
}
None
}
- fn error_struct_lit_not_allowed_here(&self, lo: Span, sp: Span) {
- self.struct_span_err(sp, "struct literals are not allowed here")
- .multipart_suggestion(
- "surround the struct literal with parentheses",
- vec![(lo.shrink_to_lo(), "(".to_string()), (sp.shrink_to_hi(), ")".to_string())],
- Applicability::MachineApplicable,
- )
- .emit();
- }
-
pub(super) fn parse_struct_fields(
&mut self,
pth: ast::Path,
@@ -3137,6 +3144,8 @@ impl<'a> Parser<'a> {
&& this.token.kind == token::Semi
{
TrailingToken::Semi
+ } else if this.token.kind == token::Gt {
+ TrailingToken::Gt
} else {
// FIXME - pass this through from the place where we know
// we need a comma, rather than assuming that `#[attr] expr,`
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 4d0a8b05e..fa75670b2 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -1,7 +1,9 @@
use super::{ForceCollect, Parser, TrailingToken};
use rustc_ast::token;
-use rustc_ast::{self as ast, AttrVec, GenericBounds, GenericParam, GenericParamKind, WhereClause};
+use rustc_ast::{
+ self as ast, AttrVec, GenericBounds, GenericParam, GenericParamKind, TyKind, WhereClause,
+};
use rustc_errors::{Applicability, PResult};
use rustc_span::symbol::kw;
@@ -31,13 +33,43 @@ impl<'a> Parser<'a> {
let mut colon_span = None;
let bounds = if self.eat(&token::Colon) {
colon_span = Some(self.prev_token.span);
+ // recover from `impl Trait` in type param bound
+ if self.token.is_keyword(kw::Impl) {
+ let impl_span = self.token.span;
+ let snapshot = self.create_snapshot_for_diagnostic();
+ match self.parse_ty() {
+ Ok(p) => {
+ if let TyKind::ImplTrait(_, bounds) = &(*p).kind {
+ let span = impl_span.to(self.token.span.shrink_to_lo());
+ let mut err = self.struct_span_err(
+ span,
+ "expected trait bound, found `impl Trait` type",
+ );
+ err.span_label(span, "not a trait");
+ if let [bound, ..] = &bounds[..] {
+ err.span_suggestion_verbose(
+ impl_span.until(bound.span()),
+ "use the trait bounds directly",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ }
+ err.emit();
+ return Err(err);
+ }
+ }
+ Err(err) => {
+ err.cancel();
+ }
+ }
+ self.restore_snapshot(snapshot);
+ }
self.parse_generic_bounds(colon_span)?
} else {
Vec::new()
};
let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
-
Ok(GenericParam {
ident,
id: ast::DUMMY_NODE_ID,
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index e55b5ce71..bda301c52 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1,4 +1,6 @@
-use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error};
+use crate::errors::{DocCommentDoesNotDocumentAnything, UseEmptyBlockNotSemi};
+
+use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
@@ -13,7 +15,7 @@ use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, Vari
use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind};
use rustc_ast::{MacArgs, MacCall, MacDelimiter};
use rustc_ast_pretty::pprust;
-use rustc_errors::{struct_span_err, Applicability, PResult, StashKey};
+use rustc_errors::{struct_span_err, Applicability, IntoDiagnostic, PResult, StashKey};
use rustc_span::edition::Edition;
use rustc_span::lev_distance::lev_distance;
use rustc_span::source_map::{self, Span};
@@ -664,6 +666,14 @@ impl<'a> Parser<'a> {
mut parse_item: impl FnMut(&mut Parser<'a>) -> PResult<'a, Option<Option<T>>>,
) -> PResult<'a, Vec<T>> {
let open_brace_span = self.token.span;
+
+ // Recover `impl Ty;` instead of `impl Ty {}`
+ if self.token == TokenKind::Semi {
+ self.sess.emit_err(UseEmptyBlockNotSemi { span: self.token.span });
+ self.bump();
+ return Ok(vec![]);
+ }
+
self.expect(&token::OpenDelim(Delimiter::Brace))?;
attrs.extend(self.parse_inner_attributes()?);
@@ -750,8 +760,8 @@ impl<'a> Parser<'a> {
)
.span_label(self.token.span, "this doc comment doesn't document anything")
.help(
- "doc comments must come before what they document, maybe a \
- comment was intended with `//`?",
+ "doc comments must come before what they document, if a comment was \
+ intended use `//`",
)
.emit();
self.bump();
@@ -1283,12 +1293,10 @@ impl<'a> Parser<'a> {
/// Parses an enum declaration.
fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> {
if self.token.is_keyword(kw::Struct) {
- let mut err = self.struct_span_err(
- self.prev_token.span.to(self.token.span),
- "`enum` and `struct` are mutually exclusive",
- );
+ let span = self.prev_token.span.to(self.token.span);
+ let mut err = self.struct_span_err(span, "`enum` and `struct` are mutually exclusive");
err.span_suggestion(
- self.prev_token.span.to(self.token.span),
+ span,
"replace `enum struct` with",
"enum",
Applicability::MachineApplicable,
@@ -1305,12 +1313,20 @@ impl<'a> Parser<'a> {
let mut generics = self.parse_generics()?;
generics.where_clause = self.parse_where_clause()?;
- let (variants, _) = self
- .parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant())
- .map_err(|e| {
- self.recover_stmt();
- e
- })?;
+ // Possibly recover `enum Foo;` instead of `enum Foo {}`
+ let (variants, _) = if self.token == TokenKind::Semi {
+ self.sess.emit_err(UseEmptyBlockNotSemi { span: self.token.span });
+ self.bump();
+ (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");
+ self.recover_stmt();
+ e
+ },
+ )?
+ };
let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() };
Ok((id, ItemKind::Enum(enum_definition, generics)))
@@ -1332,7 +1348,8 @@ impl<'a> Parser<'a> {
let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) {
// Parse a struct variant.
- let (fields, recovered) = this.parse_record_struct_body("struct", false)?;
+ let (fields, recovered) =
+ this.parse_record_struct_body("struct", ident.span, false)?;
VariantData::Struct(fields, recovered)
} else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) {
VariantData::Tuple(this.parse_tuple_struct_body()?, DUMMY_NODE_ID)
@@ -1386,8 +1403,11 @@ impl<'a> Parser<'a> {
VariantData::Unit(DUMMY_NODE_ID)
} else {
// If we see: `struct Foo<T> where T: Copy { ... }`
- let (fields, recovered) =
- self.parse_record_struct_body("struct", generics.where_clause.has_where_token)?;
+ let (fields, recovered) = self.parse_record_struct_body(
+ "struct",
+ class_name.span,
+ generics.where_clause.has_where_token,
+ )?;
VariantData::Struct(fields, recovered)
}
// No `where` so: `struct Foo<T>;`
@@ -1395,8 +1415,11 @@ impl<'a> Parser<'a> {
VariantData::Unit(DUMMY_NODE_ID)
// Record-style struct definition
} else if self.token == token::OpenDelim(Delimiter::Brace) {
- let (fields, recovered) =
- self.parse_record_struct_body("struct", generics.where_clause.has_where_token)?;
+ let (fields, recovered) = self.parse_record_struct_body(
+ "struct",
+ class_name.span,
+ generics.where_clause.has_where_token,
+ )?;
VariantData::Struct(fields, recovered)
// Tuple-style struct definition with optional where-clause.
} else if self.token == token::OpenDelim(Delimiter::Parenthesis) {
@@ -1425,12 +1448,18 @@ impl<'a> Parser<'a> {
let vdata = if self.token.is_keyword(kw::Where) {
generics.where_clause = self.parse_where_clause()?;
- let (fields, recovered) =
- self.parse_record_struct_body("union", generics.where_clause.has_where_token)?;
+ let (fields, recovered) = self.parse_record_struct_body(
+ "union",
+ class_name.span,
+ generics.where_clause.has_where_token,
+ )?;
VariantData::Struct(fields, recovered)
} else if self.token == token::OpenDelim(Delimiter::Brace) {
- let (fields, recovered) =
- self.parse_record_struct_body("union", generics.where_clause.has_where_token)?;
+ let (fields, recovered) = self.parse_record_struct_body(
+ "union",
+ class_name.span,
+ generics.where_clause.has_where_token,
+ )?;
VariantData::Struct(fields, recovered)
} else {
let token_str = super::token_descr(&self.token);
@@ -1446,6 +1475,7 @@ impl<'a> Parser<'a> {
fn parse_record_struct_body(
&mut self,
adt_ty: &str,
+ ident_span: Span,
parsed_where: bool,
) -> PResult<'a, (Vec<FieldDef>, /* recovered */ bool)> {
let mut fields = Vec::new();
@@ -1460,6 +1490,7 @@ impl<'a> Parser<'a> {
match field {
Ok(field) => fields.push(field),
Err(mut err) => {
+ err.span_label(ident_span, format!("while parsing this {adt_ty}"));
err.emit();
break;
}
@@ -1555,7 +1586,10 @@ impl<'a> Parser<'a> {
token::CloseDelim(Delimiter::Brace) => {}
token::DocComment(..) => {
let previous_span = self.prev_token.span;
- let mut err = self.span_err(self.token.span, Error::UselessDocComment);
+ let mut err = DocCommentDoesNotDocumentAnything {
+ span: self.token.span,
+ missing_comma: None,
+ };
self.bump(); // consume the doc comment
let comma_after_doc_seen = self.eat(&token::Comma);
// `seen_comma` is always false, because we are inside doc block
@@ -1564,18 +1598,13 @@ impl<'a> Parser<'a> {
seen_comma = true;
}
if comma_after_doc_seen || self.token == token::CloseDelim(Delimiter::Brace) {
- err.emit();
+ self.sess.emit_err(err);
} else {
if !seen_comma {
- let sp = self.sess.source_map().next_point(previous_span);
- err.span_suggestion(
- sp,
- "missing comma here",
- ",",
- Applicability::MachineApplicable,
- );
+ let sp = previous_span.shrink_to_hi();
+ err.missing_comma = Some(sp);
}
- return Err(err);
+ return Err(err.into_diagnostic(&self.sess.span_diagnostic));
}
}
_ => {
@@ -1715,6 +1744,7 @@ impl<'a> Parser<'a> {
fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
let (ident, is_raw) = self.ident_or_err()?;
if !is_raw && ident.is_reserved() {
+ let snapshot = self.create_snapshot_for_diagnostic();
let err = if self.check_fn_front_matter(false) {
let inherited_vis = Visibility {
span: rustc_span::DUMMY_SP,
@@ -1723,20 +1753,63 @@ impl<'a> Parser<'a> {
};
// We use `parse_fn` to get a span for the function
let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
- if let Err(mut db) =
- self.parse_fn(&mut AttrVec::new(), fn_parse_mode, lo, &inherited_vis)
+ match self.parse_fn(&mut AttrVec::new(), fn_parse_mode, lo, &inherited_vis) {
+ Ok(_) => {
+ let mut err = self.struct_span_err(
+ lo.to(self.prev_token.span),
+ &format!("functions are not allowed in {adt_ty} definitions"),
+ );
+ err.help(
+ "unlike in C++, Java, and C#, functions are declared in `impl` blocks",
+ );
+ err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information");
+ err
+ }
+ Err(err) => {
+ err.cancel();
+ self.restore_snapshot(snapshot);
+ self.expected_ident_found()
+ }
+ }
+ } else if self.eat_keyword(kw::Struct) {
+ match self.parse_item_struct() {
+ Ok((ident, _)) => {
+ let mut err = self.struct_span_err(
+ lo.with_hi(ident.span.hi()),
+ &format!("structs are not allowed in {adt_ty} definitions"),
+ );
+ err.help("consider creating a new `struct` definition instead of nesting");
+ err
+ }
+ Err(err) => {
+ err.cancel();
+ self.restore_snapshot(snapshot);
+ self.expected_ident_found()
+ }
+ }
+ } else {
+ let mut err = self.expected_ident_found();
+ if self.eat_keyword_noexpect(kw::Let)
+ && let removal_span = self.prev_token.span.until(self.token.span)
+ && let Ok(ident) = self.parse_ident_common(false)
+ // Cancel this error, we don't need it.
+ .map_err(|err| err.cancel())
+ && self.token.kind == TokenKind::Colon
{
- db.delay_as_bug();
+ err.span_suggestion(
+ removal_span,
+ "remove this `let` keyword",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ err.note("the `let` keyword is not allowed in `struct` fields");
+ err.note("see <https://doc.rust-lang.org/book/ch05-01-defining-structs.html> for more information");
+ err.emit();
+ return Ok(ident);
+ } else {
+ self.restore_snapshot(snapshot);
}
- let mut err = self.struct_span_err(
- lo.to(self.prev_token.span),
- &format!("functions are not allowed in {adt_ty} definitions"),
- );
- err.help("unlike in C++, Java, and C#, functions are declared in `impl` blocks");
- err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information");
err
- } else {
- self.expected_ident_found()
};
return Err(err);
}
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 4cb198561..5fe29062b 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -13,7 +13,6 @@ mod ty;
use crate::lexer::UnmatchedBrace;
pub use attr_wrapper::AttrWrapper;
pub use diagnostics::AttemptLocalParseRecovery;
-use diagnostics::Error;
pub(crate) use item::FnParseMode;
pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
pub use path::PathStyle;
@@ -32,7 +31,7 @@ use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::PResult;
use rustc_errors::{
- struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan,
+ Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, IntoDiagnostic, MultiSpan,
};
use rustc_session::parse::ParseSess;
use rustc_span::source_map::{Span, DUMMY_SP};
@@ -41,6 +40,11 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
use std::ops::Range;
use std::{cmp, mem, slice};
+use crate::errors::{
+ DocCommentDoesNotDocumentAnything, IncorrectVisibilityRestriction, MismatchedClosingDelimiter,
+ NonStringAbiLiteral,
+};
+
bitflags::bitflags! {
struct Restrictions: u8 {
const STMT_EXPR = 1 << 0;
@@ -75,6 +79,7 @@ pub enum ForceCollect {
pub enum TrailingToken {
None,
Semi,
+ Gt,
/// If the trailing token is a comma, then capture it
/// Otherwise, ignore the trailing token
MaybeComma,
@@ -110,6 +115,12 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath {
};
}
+#[derive(Clone, Copy)]
+pub enum Recovery {
+ Allowed,
+ Forbidden,
+}
+
#[derive(Clone)]
pub struct Parser<'a> {
pub sess: &'a ParseSess,
@@ -147,12 +158,15 @@ pub struct Parser<'a> {
/// This allows us to recover when the user forget to add braces around
/// multiple statements in the closure body.
pub current_closure: Option<ClosureSpans>,
+ /// Whether the parser is allowed to do recovery.
+ /// This is disabled when parsing macro arguments, see #103534
+ pub recovery: Recovery,
}
-// This type is used a lot, e.g. it's cloned when matching many declarative macro rules. Make sure
+// 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<'_>, 328);
+rustc_data_structures::static_assert_size!(Parser<'_>, 336);
/// Stores span information about a closure.
#[derive(Clone)]
@@ -298,7 +312,10 @@ impl TokenCursor {
fn desugar(&mut self, attr_style: AttrStyle, data: Symbol, span: Span) -> (Token, Spacing) {
// Searches for the occurrences of `"#*` and returns the minimum number of `#`s
- // required to wrap the text.
+ // required to wrap the text. E.g.
+ // - `abc d` is wrapped as `r"abc d"` (num_of_hashes = 0)
+ // - `abc "d"` is wrapped as `r#"abc "d""#` (num_of_hashes = 1)
+ // - `abc "##d##"` is wrapped as `r###"abc "d""###` (num_of_hashes = 3)
let mut num_of_hashes = 0;
let mut count = 0;
for ch in data.as_str().chars() {
@@ -310,6 +327,7 @@ impl TokenCursor {
num_of_hashes = cmp::max(num_of_hashes, count);
}
+ // `/// foo` becomes `doc = r"foo".
let delim_span = DelimSpan::from_single(span);
let body = TokenTree::Delimited(
delim_span,
@@ -406,24 +424,39 @@ pub enum FollowedByType {
No,
}
-fn token_descr_opt(token: &Token) -> Option<&'static str> {
- Some(match token.kind {
- _ if token.is_special_ident() => "reserved identifier",
- _ if token.is_used_keyword() => "keyword",
- _ if token.is_unused_keyword() => "reserved keyword",
- token::DocComment(..) => "doc comment",
- _ => return None,
- })
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum TokenDescription {
+ ReservedIdentifier,
+ Keyword,
+ ReservedKeyword,
+ DocComment,
}
-pub(super) fn token_descr(token: &Token) -> String {
- let token_str = pprust::token_to_string(token);
- match token_descr_opt(token) {
- Some(prefix) => format!("{} `{}`", prefix, token_str),
- _ => format!("`{}`", token_str),
+impl TokenDescription {
+ pub fn from_token(token: &Token) -> Option<Self> {
+ match token.kind {
+ _ if token.is_special_ident() => Some(TokenDescription::ReservedIdentifier),
+ _ if token.is_used_keyword() => Some(TokenDescription::Keyword),
+ _ if token.is_unused_keyword() => Some(TokenDescription::ReservedKeyword),
+ token::DocComment(..) => Some(TokenDescription::DocComment),
+ _ => None,
+ }
}
}
+pub(super) fn token_descr(token: &Token) -> String {
+ let name = pprust::token_to_string(token).to_string();
+
+ let kind = TokenDescription::from_token(token).map(|kind| match kind {
+ TokenDescription::ReservedIdentifier => "reserved identifier",
+ TokenDescription::Keyword => "keyword",
+ TokenDescription::ReservedKeyword => "reserved keyword",
+ TokenDescription::DocComment => "doc comment",
+ });
+
+ if let Some(kind) = kind { format!("{} `{}`", kind, name) } else { format!("`{}`", name) }
+}
+
impl<'a> Parser<'a> {
pub fn new(
sess: &'a ParseSess,
@@ -459,6 +492,7 @@ impl<'a> Parser<'a> {
inner_attr_ranges: Default::default(),
},
current_closure: None,
+ recovery: Recovery::Allowed,
};
// Make parser point to the first token.
@@ -467,6 +501,22 @@ impl<'a> Parser<'a> {
parser
}
+ pub fn forbid_recovery(mut self) -> Self {
+ self.recovery = Recovery::Forbidden;
+ self
+ }
+
+ /// Whether the parser is allowed to recover from broken code.
+ ///
+ /// If this returns false, recovering broken code into valid code (especially if this recovery does lookahead)
+ /// is not allowed. All recovery done by the parser must be gated behind this check.
+ ///
+ /// Technically, this only needs to restrict eager recovery by doing lookahead at more tokens.
+ /// But making the distinction is very subtle, and simply forbidding all recovery is a lot simpler to uphold.
+ fn may_recover(&self) -> bool {
+ matches!(self.recovery, Recovery::Allowed)
+ }
+
pub fn unexpected<T>(&mut self) -> PResult<'a, T> {
match self.expect_one_of(&[], &[]) {
Err(e) => Err(e),
@@ -518,9 +568,11 @@ impl<'a> Parser<'a> {
fn ident_or_err(&mut self) -> PResult<'a, (Ident, /* is_raw */ bool)> {
self.token.ident().ok_or_else(|| match self.prev_token.kind {
- TokenKind::DocComment(..) => {
- self.span_err(self.prev_token.span, Error::UselessDocComment)
+ TokenKind::DocComment(..) => DocCommentDoesNotDocumentAnything {
+ span: self.prev_token.span,
+ missing_comma: None,
}
+ .into_diagnostic(&self.sess.span_diagnostic),
_ => self.expected_ident_found(),
})
}
@@ -1144,7 +1196,9 @@ impl<'a> Parser<'a> {
fn parse_field_name(&mut self) -> PResult<'a, Ident> {
if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = self.token.kind
{
- self.expect_no_suffix(self.token.span, "a tuple index", suffix);
+ if let Some(suffix) = suffix {
+ self.expect_no_tuple_index_suffix(self.token.span, suffix);
+ }
self.bump();
Ok(Ident::new(symbol, self.prev_token.span))
} else {
@@ -1342,23 +1396,8 @@ impl<'a> Parser<'a> {
let path = self.parse_path(PathStyle::Mod)?;
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
- let msg = "incorrect visibility restriction";
- let suggestion = r##"some possible visibility restrictions are:
-`pub(crate)`: visible only on the current crate
-`pub(super)`: visible only in the current module's parent
-`pub(in path::to::module)`: visible only on the specified path"##;
-
let path_str = pprust::path_to_string(&path);
-
- struct_span_err!(self.sess.span_diagnostic, path.span, E0704, "{}", msg)
- .help(suggestion)
- .span_suggestion(
- path.span,
- &format!("make this visible only to module `{}` with `in`", path_str),
- format!("in {}", path_str),
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(IncorrectVisibilityRestriction { span: path.span, inner_str: path_str });
Ok(())
}
@@ -1384,14 +1423,7 @@ impl<'a> Parser<'a> {
Err(Some(lit)) => match lit.kind {
ast::LitKind::Err => None,
_ => {
- self.struct_span_err(lit.span, "non-string ABI literal")
- .span_suggestion(
- lit.span,
- "specify the ABI with a string literal",
- "\"C\"",
- Applicability::MaybeIncorrect,
- )
- .emit();
+ self.sess.emit_err(NonStringAbiLiteral { span: lit.span });
None
}
},
@@ -1432,25 +1464,18 @@ pub(crate) fn make_unclosed_delims_error(
// `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to
// `unmatched_braces` only for error recovery in the `Parser`.
let found_delim = unmatched.found_delim?;
- let span: MultiSpan = if let Some(sp) = unmatched.unclosed_span {
- vec![unmatched.found_span, sp].into()
- } else {
- unmatched.found_span.into()
- };
- let mut err = sess.span_diagnostic.struct_span_err(
- span,
- &format!(
- "mismatched closing delimiter: `{}`",
- pprust::token_kind_to_string(&token::CloseDelim(found_delim)),
- ),
- );
- err.span_label(unmatched.found_span, "mismatched closing delimiter");
- if let Some(sp) = unmatched.candidate_span {
- err.span_label(sp, "closing delimiter possibly meant for this");
- }
+ let mut spans = vec![unmatched.found_span];
if let Some(sp) = unmatched.unclosed_span {
- err.span_label(sp, "unclosed delimiter");
- }
+ spans.push(sp);
+ };
+ let err = MismatchedClosingDelimiter {
+ spans,
+ delimiter: pprust::token_kind_to_string(&token::CloseDelim(found_delim)).to_string(),
+ unmatched: unmatched.found_span,
+ opening_candidate: unmatched.candidate_span,
+ unclosed: unmatched.unclosed_span,
+ }
+ .into_diagnostic(&sess.span_diagnostic);
Some(err)
}
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 120a3c267..52c11b4e3 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1,5 +1,5 @@
use super::{ForceCollect, Parser, PathStyle, TrailingToken};
-use crate::parser::diagnostics::RemoveLet;
+use crate::errors::RemoveLet;
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
use rustc_ast::ptr::P;
@@ -10,6 +10,7 @@ use rustc_ast::{
};
use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
+use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::source_map::{respan, Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident};
@@ -401,6 +402,25 @@ impl<'a> Parser<'a> {
} else {
PatKind::Path(qself, path)
}
+ } else if matches!(self.token.kind, token::Lifetime(_))
+ // In pattern position, we're totally fine with using "next token isn't colon"
+ // as a heuristic. We could probably just always try to recover if it's a lifetime,
+ // because we never have `'a: label {}` in a pattern position anyways, but it does
+ // keep us from suggesting something like `let 'a: Ty = ..` => `let 'a': Ty = ..`
+ && !self.look_ahead(1, |token| matches!(token.kind, token::Colon))
+ {
+ // Recover a `'a` as a `'a'` literal
+ let lt = self.expect_lifetime();
+ let lit = self.recover_unclosed_char(lt.ident, |self_| {
+ let expected = expected.unwrap_or("pattern");
+ let msg =
+ format!("expected {}, found {}", expected, super::token_descr(&self_.token));
+
+ let mut err = self_.struct_span_err(self_.token.span, &msg);
+ err.span_label(self_.token.span, format!("expected {}", expected));
+ err
+ });
+ PatKind::Lit(self.mk_expr(lo, ExprKind::Lit(lit)))
} else {
// Try to parse everything else as literal with optional minus
match self.parse_literal_maybe_minus() {
@@ -693,7 +713,7 @@ impl<'a> Parser<'a> {
let sp = self.sess.source_map().start_point(self.token.span);
if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
- self.sess.expr_parentheses_needed(&mut err, *sp);
+ err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
}
Err(err)
@@ -776,7 +796,6 @@ impl<'a> Parser<'a> {
/// expression syntax `...expr` for splatting in expressions.
fn parse_pat_range_to(&mut self, mut re: Spanned<RangeEnd>) -> PResult<'a, PatKind> {
let end = self.parse_pat_range_end()?;
- self.sess.gated_spans.gate(sym::half_open_range_patterns, re.span.to(self.prev_token.span));
if let RangeEnd::Included(ref mut syn @ RangeSyntax::DotDotDot) = &mut re.node {
*syn = RangeSyntax::DotDotEq;
self.struct_span_err(re.span, "range-to patterns with `...` are not allowed")
@@ -799,6 +818,7 @@ impl<'a> Parser<'a> {
|| t.kind == token::Dot // e.g. `.5` for recovery;
|| t.can_begin_literal_maybe_minus() // e.g. `42`.
|| t.is_whole_expr()
+ || t.is_lifetime() // recover `'a` instead of `'a'`
})
}
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 3d957406b..12753c678 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -1,7 +1,5 @@
-use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN;
-use super::diagnostics::{
- AttemptLocalParseRecovery, Error, InvalidVariableDeclaration, InvalidVariableDeclarationSub,
-};
+use super::attr::InnerAttrForbiddenReason;
+use super::diagnostics::AttemptLocalParseRecovery;
use super::expr::LhsExpr;
use super::pat::RecoverComma;
use super::path::PathStyle;
@@ -9,6 +7,12 @@ use super::TrailingToken;
use super::{
AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode,
};
+use crate::errors::{
+ AssignmentElseNotAllowed, CompoundAssignmentExpressionInLet, ConstLetMutuallyExclusive,
+ DocCommentDoesNotDocumentAnything, ExpectedStatementAfterOuterAttr, InvalidCurlyInLetElse,
+ InvalidExpressionInLetElse, InvalidVariableDeclaration, InvalidVariableDeclarationSub,
+ WrapExpressionInParentheses,
+};
use crate::maybe_whole;
use rustc_ast as ast;
@@ -112,11 +116,7 @@ impl<'a> Parser<'a> {
let bl = self.parse_block()?;
// Destructuring assignment ... else.
// This is not allowed, but point it out in a nice way.
- let mut err = self.struct_span_err(
- e.span.to(bl.span),
- "<assignment> ... else { ... } is not allowed",
- );
- err.emit();
+ self.sess.emit_err(AssignmentElseNotAllowed { span: e.span.to(bl.span) });
}
self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
} else {
@@ -202,9 +202,12 @@ impl<'a> Parser<'a> {
fn error_outer_attrs(&self, attrs: &[Attribute]) {
if let [.., last] = attrs {
if last.is_doc_comment() {
- self.span_err(last.span, Error::UselessDocComment).emit();
+ self.sess.emit_err(DocCommentDoesNotDocumentAnything {
+ span: last.span,
+ missing_comma: None,
+ });
} else if attrs.iter().any(|a| a.style == AttrStyle::Outer) {
- self.struct_span_err(last.span, "expected statement after outer attribute").emit();
+ self.sess.emit_err(ExpectedStatementAfterOuterAttr { span: last.span });
}
}
}
@@ -255,17 +258,7 @@ impl<'a> Parser<'a> {
let lo = self.prev_token.span;
if self.token.is_keyword(kw::Const) && self.look_ahead(1, |t| t.is_ident()) {
- self.struct_span_err(
- lo.to(self.token.span),
- "`const` and `let` are mutually exclusive",
- )
- .span_suggestion(
- lo.to(self.token.span),
- "remove `let`",
- "const",
- Applicability::MaybeIncorrect,
- )
- .emit();
+ self.sess.emit_err(ConstLetMutuallyExclusive { span: lo.to(self.token.span) });
self.bump();
}
@@ -363,44 +356,27 @@ impl<'a> Parser<'a> {
fn check_let_else_init_bool_expr(&self, init: &ast::Expr) {
if let ast::ExprKind::Binary(op, ..) = init.kind {
if op.node.lazy() {
- let suggs = vec![
- (init.span.shrink_to_lo(), "(".to_string()),
- (init.span.shrink_to_hi(), ")".to_string()),
- ];
- self.struct_span_err(
- init.span,
- &format!(
- "a `{}` expression cannot be directly assigned in `let...else`",
- op.node.to_string()
- ),
- )
- .multipart_suggestion(
- "wrap the expression in parentheses",
- suggs,
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(InvalidExpressionInLetElse {
+ span: init.span,
+ operator: op.node.to_string(),
+ sugg: WrapExpressionInParentheses {
+ left: init.span.shrink_to_lo(),
+ right: init.span.shrink_to_hi(),
+ },
+ });
}
}
}
fn check_let_else_init_trailing_brace(&self, init: &ast::Expr) {
if let Some(trailing) = classify::expr_trailing_brace(init) {
- let err_span = trailing.span.with_lo(trailing.span.hi() - BytePos(1));
- let suggs = vec![
- (trailing.span.shrink_to_lo(), "(".to_string()),
- (trailing.span.shrink_to_hi(), ")".to_string()),
- ];
- self.struct_span_err(
- err_span,
- "right curly brace `}` before `else` in a `let...else` statement not allowed",
- )
- .multipart_suggestion(
- "try wrapping the expression in parentheses",
- suggs,
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(InvalidCurlyInLetElse {
+ span: trailing.span.with_lo(trailing.span.hi() - BytePos(1)),
+ sugg: WrapExpressionInParentheses {
+ left: trailing.span.shrink_to_lo(),
+ right: trailing.span.shrink_to_hi(),
+ },
+ });
}
}
@@ -409,18 +385,7 @@ impl<'a> Parser<'a> {
let eq_consumed = match self.token.kind {
token::BinOpEq(..) => {
// Recover `let x <op>= 1` as `let x = 1`
- self.struct_span_err(
- self.token.span,
- "can't reassign to an uninitialized variable",
- )
- .span_suggestion_short(
- self.token.span,
- "initialize the variable",
- "=",
- Applicability::MaybeIncorrect,
- )
- .help("if you meant to overwrite, remove the `let` binding")
- .emit();
+ self.sess.emit_err(CompoundAssignmentExpressionInLet { span: self.token.span });
self.bump();
true
}
@@ -434,7 +399,12 @@ impl<'a> Parser<'a> {
pub(super) fn parse_block(&mut self) -> PResult<'a, P<Block>> {
let (attrs, block) = self.parse_inner_attrs_and_block()?;
if let [.., last] = &*attrs {
- self.error_on_forbidden_inner_attr(last.span, DEFAULT_INNER_ATTR_FORBIDDEN);
+ self.error_on_forbidden_inner_attr(
+ last.span,
+ super::attr::InnerAttrPolicy::Forbidden(Some(
+ InnerAttrForbiddenReason::InCodeBlock,
+ )),
+ );
}
Ok(block)
}
@@ -583,39 +553,46 @@ impl<'a> Parser<'a> {
match stmt.kind {
// Expression without semicolon.
StmtKind::Expr(ref mut expr)
- if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(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.
- if let Err(mut e) =
- self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)])
- {
- if let TokenKind::DocComment(..) = self.token.kind {
- if 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!(
- "add a space before `{}` to use a regular comment",
- doc_comment_marker,
- ),
- format!("{} {}", comment_marker, doc_comment_marker),
- Applicability::MaybeIncorrect,
- );
+ // `expect_one_of` returns PResult<'a, bool /* recovered */>
+ let replace_with_err =
+ match self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]) {
+ // 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) {
+ 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!(
+ "add a space before `{}` to use a regular comment",
+ doc_comment_marker,
+ ),
+ format!("{} {}", comment_marker, doc_comment_marker),
+ Applicability::MaybeIncorrect,
+ );
}
- }
- if let Err(mut e) =
- self.check_mistyped_turbofish_with_multiple_type_params(e, expr)
- {
- if recover.no() {
- return Err(e);
+
+ 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();
}
- e.emit();
- self.recover_stmt();
+ true
}
- // Don't complain about type errors in body tail after parse error (#57383).
+ _ => 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);
*expr = self.mk_expr_err(sp);
}
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index b47f0c097..2a8512acf 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -397,10 +397,13 @@ impl<'a> Parser<'a> {
fn parse_ty_ptr(&mut self) -> PResult<'a, TyKind> {
let mutbl = self.parse_const_or_mut().unwrap_or_else(|| {
let span = self.prev_token.span;
- let msg = "expected mut or const in raw pointer type";
- self.struct_span_err(span, msg)
- .span_label(span, msg)
- .help("use `*mut T` or `*const T` as appropriate")
+ self.struct_span_err(span, "expected `mut` or `const` keyword in raw pointer type")
+ .span_suggestions(
+ span.shrink_to_hi(),
+ "add `mut` or `const` here",
+ ["mut ".to_string(), "const ".to_string()].into_iter(),
+ Applicability::HasPlaceholders,
+ )
.emit();
Mutability::Not
});
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index a9e502016..1394993ab 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -224,7 +224,7 @@ impl<'a> Iterator for Parser<'a> {
'{' => {
let curr_last_brace = self.last_opening_brace;
let byte_pos = self.to_span_index(pos);
- let lbrace_end = InnerOffset(byte_pos.0 + 1);
+ let lbrace_end = self.to_span_index(pos + 1);
self.last_opening_brace = Some(byte_pos.to(lbrace_end));
self.cur.next();
if self.consume('{') {
@@ -740,20 +740,40 @@ impl<'a> Parser<'a> {
word
}
- /// Optionally parses an integer at the current position. This doesn't deal
- /// with overflow at all, it's just accumulating digits.
fn integer(&mut self) -> Option<usize> {
- let mut cur = 0;
+ let mut cur: usize = 0;
let mut found = false;
+ let mut overflow = false;
+ let start = self.current_pos();
while let Some(&(_, c)) = self.cur.peek() {
if let Some(i) = c.to_digit(10) {
- cur = cur * 10 + i as usize;
+ let (tmp, mul_overflow) = cur.overflowing_mul(10);
+ let (tmp, add_overflow) = tmp.overflowing_add(i as usize);
+ if mul_overflow || add_overflow {
+ overflow = true;
+ }
+ cur = tmp;
found = true;
self.cur.next();
} else {
break;
}
}
+
+ if overflow {
+ let end = self.current_pos();
+ let overflowed_int = &self.input[start..end];
+ self.err(
+ format!(
+ "integer `{}` does not fit into the type `usize` whose range is `0..={}`",
+ overflowed_int,
+ usize::MAX
+ ),
+ "integer out of range for `usize`",
+ self.span(start, end),
+ );
+ }
+
if found { Some(cur) } else { None }
}
diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs
index 2f8c229c6..3f9cb149b 100644
--- a/compiler/rustc_parse_format/src/tests.rs
+++ b/compiler/rustc_parse_format/src/tests.rs
@@ -58,6 +58,21 @@ fn invalid06() {
}
#[test]
+fn invalid_position() {
+ musterr("{18446744073709551616}");
+}
+
+#[test]
+fn invalid_width() {
+ musterr("{:18446744073709551616}");
+}
+
+#[test]
+fn invalid_precision() {
+ musterr("{:.18446744073709551616}");
+}
+
+#[test]
fn format_nothing() {
same(
"{}",
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index b3f15ba7c..27a57adf9 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -4,16 +4,21 @@
//! conflicts between multiple such attributes attached to the same
//! item.
-use crate::errors;
+use crate::errors::{
+ self, AttrApplication, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel, ObjectLifetimeErr,
+ OnlyHasEffectOn, TransparentIncompatible, UnrecognizedReprHint,
+};
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan};
+use rustc_errors::{fluent, Applicability, 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, CRATE_DEF_ID};
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID};
+use rustc_hir::{
+ self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID,
+};
use rustc_hir::{MethodKind, Target};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
@@ -35,8 +40,8 @@ pub(crate) fn target_from_impl_item<'tcx>(
match impl_item.kind {
hir::ImplItemKind::Const(..) => Target::AssocConst,
hir::ImplItemKind::Fn(..) => {
- let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id());
- let containing_item = tcx.hir().expect_item(parent_hir_id);
+ let parent_def_id = tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
+ let containing_item = tcx.hir().expect_item(parent_def_id);
let containing_impl_is_for_trait = match &containing_item.kind {
hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
_ => bug!("parent of an ImplItem must be an Impl"),
@@ -47,7 +52,7 @@ pub(crate) fn target_from_impl_item<'tcx>(
Target::Method(MethodKind::Inherent)
}
}
- hir::ImplItemKind::TyAlias(..) => Target::AssocTy,
+ hir::ImplItemKind::Type(..) => Target::AssocTy,
}
}
@@ -162,17 +167,17 @@ impl CheckAttrVisitor<'_> {
sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target),
sym::deprecated => self.check_deprecated(hir_id, attr, span, target),
sym::macro_use | sym::macro_escape => self.check_macro_use(hir_id, attr, target),
- sym::path => self.check_generic_attr(hir_id, attr, target, &[Target::Mod]),
+ sym::path => self.check_generic_attr(hir_id, attr, target, Target::Mod),
sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target),
sym::macro_export => self.check_macro_export(hir_id, attr, target),
sym::ignore | sym::should_panic | sym::proc_macro_derive => {
- self.check_generic_attr(hir_id, attr, target, &[Target::Fn])
+ self.check_generic_attr(hir_id, attr, target, Target::Fn)
}
sym::automatically_derived => {
- self.check_generic_attr(hir_id, attr, target, &[Target::Impl])
+ self.check_generic_attr(hir_id, attr, target, Target::Impl)
}
sym::no_implicit_prelude => {
- self.check_generic_attr(hir_id, attr, target, &[Target::Mod])
+ self.check_generic_attr(hir_id, attr, target, Target::Mod)
}
sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id),
_ => {}
@@ -263,7 +268,7 @@ impl CheckAttrVisitor<'_> {
}
// FIXME(#65833): We permit associated consts to have an `#[inline]` attribute with
// just a lint, because we previously erroneously allowed it and some crates used it
- // accidentally, to to be compatible with crates depending on them, we can't throw an
+ // accidentally, to be compatible with crates depending on them, we can't throw an
// error here.
Target::AssocConst => {
self.tcx.emit_spanned_lint(
@@ -349,29 +354,18 @@ impl CheckAttrVisitor<'_> {
hir_id: HirId,
attr: &Attribute,
target: Target,
- allowed_targets: &[Target],
+ allowed_target: Target,
) {
- if !allowed_targets.iter().any(|t| t == &target) {
- let name = attr.name_or_empty();
- let mut i = allowed_targets.iter();
- // Pluralize
- let b = i.next().map_or_else(String::new, |t| t.to_string() + "s");
- let supported_names = i.enumerate().fold(b, |mut b, (i, allowed_target)| {
- if allowed_targets.len() > 2 && i == allowed_targets.len() - 2 {
- b.push_str(", and ");
- } else if allowed_targets.len() == 2 && i == allowed_targets.len() - 2 {
- b.push_str(" and ");
- } else {
- b.push_str(", ");
- }
- // Pluralize
- b.push_str(&(allowed_target.to_string() + "s"));
- b
- });
- self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
- lint.build(&format!("`#[{name}]` only has an effect on {}", supported_names))
- .emit();
- });
+ if target != allowed_target {
+ self.tcx.emit_spanned_lint(
+ UNUSED_ATTRIBUTES,
+ hir_id,
+ attr.span,
+ OnlyHasEffectOn {
+ attr_name: attr.name_or_empty(),
+ target_name: allowed_target.name().replace(" ", "_"),
+ },
+ );
}
}
@@ -382,7 +376,7 @@ impl CheckAttrVisitor<'_> {
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[allow_internal_unstable]` attribute with just a lint, because we previously
- // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "naked");
@@ -427,7 +421,7 @@ impl CheckAttrVisitor<'_> {
ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
};
- tcx.sess.span_err(p.span, &repr);
+ tcx.sess.emit_err(ObjectLifetimeErr { span: p.span, repr });
}
}
}
@@ -462,7 +456,7 @@ impl CheckAttrVisitor<'_> {
Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true,
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[track_caller]` attribute with just a lint, because we previously
- // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
for attr in attrs {
@@ -491,7 +485,7 @@ impl CheckAttrVisitor<'_> {
Target::Struct | Target::Enum | Target::Variant => true,
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[non_exhaustive]` attribute with just a lint, because we previously
- // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "non_exhaustive");
@@ -513,7 +507,7 @@ impl CheckAttrVisitor<'_> {
Target::Trait => true,
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[marker]` attribute with just a lint, because we previously
- // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "marker");
@@ -572,7 +566,7 @@ impl CheckAttrVisitor<'_> {
}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[target_feature]` attribute with just a lint, because we previously
- // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "target_feature");
@@ -640,8 +634,8 @@ impl CheckAttrVisitor<'_> {
let span = meta.span();
if let Some(location) = match target {
Target::AssocTy => {
- let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
- let containing_item = self.tcx.hir().expect_item(parent_hir_id);
+ let parent_def_id = self.tcx.hir().get_parent_item(hir_id).def_id;
+ let containing_item = self.tcx.hir().expect_item(parent_def_id);
if Target::from_item(containing_item) == Target::Impl {
Some("type alias in implementation block")
} else {
@@ -649,8 +643,8 @@ impl CheckAttrVisitor<'_> {
}
}
Target::AssocConst => {
- let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
- let containing_item = self.tcx.hir().expect_item(parent_hir_id);
+ let parent_def_id = self.tcx.hir().get_parent_item(hir_id).def_id;
+ let containing_item = self.tcx.hir().expect_item(parent_def_id);
// We can't link to trait impl's consts.
let err = "associated constant in trait implementation block";
match containing_item.kind {
@@ -828,8 +822,8 @@ impl CheckAttrVisitor<'_> {
if let Some((prev_inline, prev_span)) = *specified_inline {
if do_inline != prev_inline {
let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]);
- spans.push_span_label(prev_span, fluent::passes::doc_inline_conflict_first);
- spans.push_span_label(meta.span(), fluent::passes::doc_inline_conflict_second);
+ spans.push_span_label(prev_span, fluent::passes_doc_inline_conflict_first);
+ spans.push_span_label(meta.span(), fluent::passes_doc_inline_conflict_second);
self.tcx.sess.emit_err(errors::DocKeywordConflict { spans });
return false;
}
@@ -875,25 +869,31 @@ impl CheckAttrVisitor<'_> {
hir_id: HirId,
) -> bool {
if hir_id != CRATE_HIR_ID {
- self.tcx.struct_span_lint_hir(INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), |lint| {
- let mut err = lint.build(fluent::passes::attr_crate_level);
- if attr.style == AttrStyle::Outer
- && self.tcx.hir().get_parent_item(hir_id) == CRATE_DEF_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);
+ self.tcx.struct_span_lint_hir(
+ 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::suggestion,
+ src,
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.span_help(attr.span, fluent::help);
+ }
}
- }
- err.note(fluent::passes::note).emit();
- });
+ err.note(fluent::note);
+ err
+ },
+ );
return false;
}
true
@@ -934,6 +934,22 @@ impl CheckAttrVisitor<'_> {
is_valid
}
+ /// Check that the `#![doc(cfg_hide(...))]` attribute only contains a list of attributes.
+ /// Returns `true` if valid.
+ fn check_doc_cfg_hide(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
+ if meta.meta_item_list().is_some() {
+ true
+ } else {
+ self.tcx.emit_spanned_lint(
+ INVALID_DOC_ATTRIBUTES,
+ hir_id,
+ meta.span(),
+ errors::DocCfgHideTakesList,
+ );
+ false
+ }
+ }
+
/// Runs various checks on `#[doc]` attributes. Returns `true` if valid.
///
/// `specified_inline` should be initialized to `None` and kept for the scope
@@ -987,6 +1003,13 @@ impl CheckAttrVisitor<'_> {
is_valid = false;
}
+ sym::cfg_hide
+ if !self.check_attr_crate_level(attr, meta, hir_id)
+ || !self.check_doc_cfg_hide(meta, hir_id) =>
+ {
+ is_valid = false;
+ }
+
sym::inline | sym::no_inline
if !self.check_doc_inline(
attr,
@@ -1205,7 +1228,7 @@ impl CheckAttrVisitor<'_> {
Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[cold]` attribute with just a lint, because we previously
- // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "cold");
@@ -1247,7 +1270,7 @@ impl CheckAttrVisitor<'_> {
Target::ForeignFn | Target::ForeignStatic => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[link_name]` attribute with just a lint, because we previously
- // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_name");
@@ -1281,7 +1304,7 @@ impl CheckAttrVisitor<'_> {
Target::ExternCrate => true,
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[no_link]` attribute with just a lint, because we previously
- // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link");
@@ -1311,7 +1334,7 @@ impl CheckAttrVisitor<'_> {
Target::Method(..) if self.is_impl_item(hir_id) => true,
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[export_name]` attribute with just a lint, because we previously
- // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name");
@@ -1503,7 +1526,7 @@ impl CheckAttrVisitor<'_> {
Target::Static | Target::Fn | Target::Method(..) => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[link_section]` attribute with just a lint, because we previously
- // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_section");
@@ -1528,7 +1551,7 @@ impl CheckAttrVisitor<'_> {
Target::Method(..) if self.is_impl_item(hir_id) => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
// `#[no_mangle]` attribute with just a lint, because we previously
- // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_mangle");
@@ -1594,12 +1617,17 @@ impl CheckAttrVisitor<'_> {
continue;
}
- let (article, allowed_targets) = match hint.name_or_empty() {
+ match hint.name_or_empty() {
sym::C => {
is_c = true;
match target {
Target::Struct | Target::Union | Target::Enum => continue,
- _ => ("a", "struct, enum, or union"),
+ _ => {
+ self.tcx.sess.emit_err(AttrApplication::StructEnumUnion {
+ hint_span: hint.span(),
+ span,
+ });
+ }
}
}
sym::align => {
@@ -1615,12 +1643,20 @@ impl CheckAttrVisitor<'_> {
match target {
Target::Struct | Target::Union | Target::Enum | Target::Fn => continue,
- _ => ("a", "struct, enum, function, or union"),
+ _ => {
+ self.tcx.sess.emit_err(AttrApplication::StructEnumFunctionUnion {
+ hint_span: hint.span(),
+ span,
+ });
+ }
}
}
sym::packed => {
if target != Target::Struct && target != Target::Union {
- ("a", "struct or union")
+ self.tcx.sess.emit_err(AttrApplication::StructUnion {
+ hint_span: hint.span(),
+ span,
+ });
} else {
continue;
}
@@ -1628,7 +1664,9 @@ impl CheckAttrVisitor<'_> {
sym::simd => {
is_simd = true;
if target != Target::Struct {
- ("a", "struct")
+ self.tcx
+ .sess
+ .emit_err(AttrApplication::Struct { hint_span: hint.span(), span });
} else {
continue;
}
@@ -1637,7 +1675,12 @@ impl CheckAttrVisitor<'_> {
is_transparent = true;
match target {
Target::Struct | Target::Union | Target::Enum => continue,
- _ => ("a", "struct, enum, or union"),
+ _ => {
+ self.tcx.sess.emit_err(AttrApplication::StructEnumUnion {
+ hint_span: hint.span(),
+ span,
+ });
+ }
}
}
sym::i8
@@ -1654,35 +1697,18 @@ impl CheckAttrVisitor<'_> {
| sym::usize => {
int_reprs += 1;
if target != Target::Enum {
- ("an", "enum")
+ self.tcx
+ .sess
+ .emit_err(AttrApplication::Enum { hint_span: hint.span(), span });
} else {
continue;
}
}
_ => {
- struct_span_err!(
- self.tcx.sess,
- hint.span(),
- E0552,
- "unrecognized representation hint"
- )
- .help("valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, \
- `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`")
- .emit();
-
+ self.tcx.sess.emit_err(UnrecognizedReprHint { span: hint.span() });
continue;
}
};
-
- struct_span_err!(
- self.tcx.sess,
- hint.span(),
- E0517,
- "{}",
- &format!("attribute should be applied to {article} {allowed_targets}")
- )
- .span_label(span, &format!("not {article} {allowed_targets}"))
- .emit();
}
// Just point at all repr hints if there are any incompatibilities.
@@ -1692,14 +1718,9 @@ impl CheckAttrVisitor<'_> {
// Error on repr(transparent, <anything else>).
if is_transparent && hints.len() > 1 {
let hint_spans: Vec<_> = hint_spans.clone().collect();
- struct_span_err!(
- self.tcx.sess,
- hint_spans,
- E0692,
- "transparent {} cannot have other repr hints",
- target
- )
- .emit();
+ self.tcx
+ .sess
+ .emit_err(TransparentIncompatible { hint_spans, target: target.to_string() });
}
// Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
if (int_reprs > 1)
@@ -1742,7 +1763,7 @@ impl CheckAttrVisitor<'_> {
}
}
Some(_) => {
- // This error case is handled in rustc_typeck::collect.
+ // This error case is handled in rustc_hir_analysis::collect.
}
None => {
// Default case (compiler) when arg isn't defined.
@@ -1784,7 +1805,7 @@ impl CheckAttrVisitor<'_> {
Target::MacroDef => true,
// FIXME(#80564): We permit struct fields and match arms to have an
// `#[allow_internal_unstable]` attribute with just a lint, because we previously
- // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm => {
self.inline_attr_str_error_without_macro_def(
@@ -1851,14 +1872,12 @@ impl CheckAttrVisitor<'_> {
match std::fs::File::open(&file) {
Ok(_) => true,
- Err(err) => {
- self.tcx
- .sess
- .struct_span_err(
- meta_item.span,
- &format!("couldn't read {}: {}", file.display(), err),
- )
- .emit();
+ Err(error) => {
+ self.tcx.sess.emit_err(DebugVisualizerUnreadable {
+ span: meta_item.span,
+ file: &file,
+ error,
+ });
false
}
}
@@ -1881,7 +1900,7 @@ impl CheckAttrVisitor<'_> {
}
// FIXME(#80564): We permit struct fields and match arms to have an
// `#[allow_internal_unstable]` attribute with just a lint, because we previously
- // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr, "allow_internal_unstable");
@@ -2043,7 +2062,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
// so this lets us continue to run them while maintaining backwards compatibility.
// In the long run, the checks should be harmonized.
if let ItemKind::Macro(ref macro_def, _) = item.kind {
- let def_id = item.def_id.to_def_id();
+ let def_id = item.owner_id.to_def_id();
if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) {
check_non_exported_macro_for_invalid_attrs(self.tcx, item);
}
@@ -2169,25 +2188,11 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
if attr.style == AttrStyle::Inner {
for attr_to_check in ATTRS_TO_CHECK {
if attr.has_name(*attr_to_check) {
- let mut err = tcx.sess.struct_span_err(
- attr.span,
- &format!(
- "`{}` attribute cannot be used at crate level",
- attr_to_check.to_ident_string()
- ),
- );
- // Only emit an error with a suggestion if we can create a
- // string out of the attribute span
- if let Ok(src) = tcx.sess.source_map().span_to_snippet(attr.span) {
- let replacement = src.replace("#!", "#");
- err.span_suggestion_verbose(
- attr.span,
- "perhaps you meant to use an outer attribute",
- replacement,
- rustc_errors::Applicability::MachineApplicable,
- );
- }
- err.emit();
+ tcx.sess.emit_err(InvalidAttrAtCrateLevel {
+ span: attr.span,
+ snippet: tcx.sess.source_map().span_to_snippet(attr.span).ok(),
+ name: *attr_to_check,
+ });
}
}
}
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 70518284c..aa726d6cd 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -8,7 +8,6 @@
//! through, but errors for structured control flow in a `const` should be emitted here.
use rustc_attr as attr;
-use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, Visitor};
@@ -18,6 +17,8 @@ use rustc_middle::ty::TyCtxt;
use rustc_session::parse::feature_err;
use rustc_span::{sym, Span, Symbol};
+use crate::errors::ExprNotAllowedInContext;
+
/// An expression that is not *always* legal in a const context.
#[derive(Clone, Copy)]
enum NonConstExpr {
@@ -133,18 +134,22 @@ impl<'tcx> CheckConstVisitor<'tcx> {
let const_kind =
const_kind.expect("`const_check_violated` may only be called inside a const context");
- let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());
-
let required_gates = required_gates.unwrap_or(&[]);
let missing_gates: Vec<_> =
required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();
match missing_gates.as_slice() {
[] => {
- struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit();
+ tcx.sess.emit_err(ExprNotAllowedInContext {
+ span,
+ expr: expr.name(),
+ context: const_kind.keyword_name(),
+ });
}
[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);
// If multiple feature gates would be required to enable this expression, include
@@ -191,10 +196,6 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
self.tcx.hir()
}
- fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
- intravisit::walk_item(self, item);
- }
-
fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
let kind = Some(hir::ConstContext::Const);
self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index f141d7bee..753d01f46 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -11,13 +11,15 @@ use rustc_hir::def_id::{DefId, LocalDefId};
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;
+use rustc_middle::middle::privacy::Level;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
use rustc_session::lint;
use rustc_span::symbol::{sym, Symbol};
use std::mem;
+use crate::errors::UselessAssignment;
+
// Any local node that may call something in its body block should be
// explored. For example, if it's a live Node::Item that is a
// function, then we should explore its block to check for codes that
@@ -102,14 +104,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
}
}
Res::Def(_, def_id) => self.check_def_id(def_id),
- Res::SelfTy { trait_: t, alias_to: i } => {
- if let Some(t) = t {
- self.check_def_id(t);
- }
- if let Some((i, _)) = i {
- self.check_def_id(i);
- }
- }
+ Res::SelfTyParam { trait_: t } => self.check_def_id(t),
+ Res::SelfTyAlias { alias_to: i, .. } => self.check_def_id(i),
Res::ToolMod | Res::NonMacroAttr(..) | Res::Err => {}
}
}
@@ -186,18 +182,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
&& !assign.span.from_expansion()
{
let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..));
- self.tcx.struct_span_lint_hir(
+ self.tcx.emit_spanned_lint(
lint::builtin::DEAD_CODE,
assign.hir_id,
assign.span,
- |lint| {
- lint.build(&format!(
- "useless assignment of {} of type `{}` to itself",
- if is_field_assign { "field" } else { "variable" },
- self.typeck_results().expr_ty(lhs),
- ))
- .emit();
- },
+ UselessAssignment { is_field_assign, ty: self.typeck_results().expr_ty(lhs) }
)
}
}
@@ -291,8 +280,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
}
fn visit_node(&mut self, node: Node<'tcx>) {
- if let Node::ImplItem(hir::ImplItem { def_id, .. }) = node
- && self.should_ignore_item(def_id.to_def_id())
+ if let Node::ImplItem(hir::ImplItem { owner_id, .. }) = node
+ && self.should_ignore_item(owner_id.to_def_id())
{
return;
}
@@ -304,7 +293,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
match node {
Node::Item(item) => match item.kind {
hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
- let def = self.tcx.adt_def(item.def_id);
+ let def = self.tcx.adt_def(item.owner_id);
self.repr_has_repr_c = def.repr().c();
self.repr_has_repr_simd = def.repr().simd();
@@ -317,7 +306,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
intravisit::walk_trait_item(self, trait_item);
}
Node::ImplItem(impl_item) => {
- let item = self.tcx.local_parent(impl_item.def_id);
+ let item = self.tcx.local_parent(impl_item.owner_id.def_id);
if self.tcx.impl_trait_ref(item).is_none() {
//// If it's a type whose items are live, then it's live, too.
//// This is done to handle the case where, for example, the static
@@ -374,7 +363,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
if has_repr_c || (f.is_positional() && has_repr_simd) {
return Some(def_id);
}
- if !tcx.visibility(f.hir_id.owner).is_public() {
+ if !tcx.visibility(f.hir_id.owner.def_id).is_public() {
return None;
}
if tcx.visibility(def_id).is_public() { Some(def_id) } else { None }
@@ -528,10 +517,10 @@ fn check_item<'tcx>(
) {
let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.hir_id());
if allow_dead_code {
- worklist.push(id.def_id);
+ worklist.push(id.owner_id.def_id);
}
- match tcx.def_kind(id.def_id) {
+ match tcx.def_kind(id.owner_id) {
DefKind::Enum => {
let item = tcx.hir().item(id);
if let hir::ItemKind::Enum(ref enum_def, _) = item.kind {
@@ -551,15 +540,15 @@ fn check_item<'tcx>(
}
}
DefKind::Impl => {
- let of_trait = tcx.impl_trait_ref(id.def_id);
+ let of_trait = tcx.impl_trait_ref(id.owner_id);
if of_trait.is_some() {
- worklist.push(id.def_id);
+ worklist.push(id.owner_id.def_id);
}
// get DefIds from another query
let local_def_ids = tcx
- .associated_item_def_ids(id.def_id)
+ .associated_item_def_ids(id.owner_id)
.iter()
.filter_map(|def_id| def_id.as_local());
@@ -577,12 +566,12 @@ fn check_item<'tcx>(
if let hir::ItemKind::Struct(ref variant_data, _) = item.kind
&& let Some(ctor_hir_id) = variant_data.ctor_hir_id()
{
- struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.def_id);
+ struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.owner_id.def_id);
}
}
DefKind::GlobalAsm => {
// global_asm! is always live.
- worklist.push(id.def_id);
+ worklist.push(id.owner_id.def_id);
}
_ => {}
}
@@ -590,12 +579,12 @@ fn check_item<'tcx>(
fn check_trait_item<'tcx>(tcx: TyCtxt<'tcx>, worklist: &mut Vec<LocalDefId>, id: hir::TraitItemId) {
use hir::TraitItemKind::{Const, Fn};
- if matches!(tcx.def_kind(id.def_id), DefKind::AssocConst | DefKind::AssocFn) {
+ if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) {
let trait_item = tcx.hir().trait_item(id);
if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_)))
&& has_allow_dead_code_or_lang_attr(tcx, trait_item.hir_id())
{
- worklist.push(trait_item.def_id);
+ worklist.push(trait_item.owner_id.def_id);
}
}
}
@@ -605,27 +594,24 @@ fn check_foreign_item<'tcx>(
worklist: &mut Vec<LocalDefId>,
id: hir::ForeignItemId,
) {
- if matches!(tcx.def_kind(id.def_id), DefKind::Static(_) | DefKind::Fn)
+ if matches!(tcx.def_kind(id.owner_id), DefKind::Static(_) | DefKind::Fn)
&& has_allow_dead_code_or_lang_attr(tcx, id.hir_id())
{
- worklist.push(id.def_id);
+ worklist.push(id.owner_id.def_id);
}
}
fn create_and_seed_worklist<'tcx>(
tcx: TyCtxt<'tcx>,
) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) {
- let access_levels = &tcx.privacy_access_levels(());
+ let effective_visibilities = &tcx.effective_visibilities(());
// see `MarkSymbolVisitor::struct_constructors`
let mut struct_constructors = Default::default();
- let mut worklist = access_levels
- .map
+ let mut worklist = effective_visibilities
.iter()
- .filter_map(
- |(&id, &level)| {
- if level >= privacy::AccessLevel::Reachable { Some(id) } else { None }
- },
- )
+ .filter_map(|(&id, effective_vis)| {
+ effective_vis.is_public_at_level(Level::Reachable).then_some(id)
+ })
// Seed entry point
.chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local()))
.collect::<Vec<_>>();
@@ -726,6 +712,26 @@ impl<'tcx> DeadVisitor<'tcx> {
})
.collect();
+ let descr = tcx.def_kind(first_id).descr(first_id.to_def_id());
+ let span_len = dead_codes.len();
+ let names = match &names[..] {
+ _ if span_len > 6 => String::new(),
+ [name] => format!("`{name}` "),
+ [names @ .., last] => {
+ format!(
+ "{} and `{last}` ",
+ names.iter().map(|name| format!("`{name}`")).join(", ")
+ )
+ }
+ [] => unreachable!(),
+ };
+ let msg = format!(
+ "{these}{descr}{s} {names}{are} never {participle}",
+ these = if span_len > 6 { "multiple " } else { "" },
+ s = pluralize!(span_len),
+ are = pluralize!("is", span_len),
+ );
+
tcx.struct_span_lint_hir(
if is_positional {
lint::builtin::UNUSED_TUPLE_STRUCT_FIELDS
@@ -734,27 +740,8 @@ impl<'tcx> DeadVisitor<'tcx> {
},
tcx.hir().local_def_id_to_hir_id(first_id),
MultiSpan::from_spans(spans.clone()),
- |lint| {
- let descr = tcx.def_kind(first_id).descr(first_id.to_def_id());
- let span_len = dead_codes.len();
- let names = match &names[..] {
- _ if span_len > 6 => String::new(),
- [name] => format!("`{name}` "),
- [names @ .., last] => {
- format!(
- "{} and `{last}` ",
- names.iter().map(|name| format!("`{name}`")).join(", ")
- )
- }
- [] => unreachable!(),
- };
- let mut err = lint.build(&format!(
- "{these}{descr}{s} {names}{are} never {participle}",
- these = if span_len > 6 { "multiple " } else { "" },
- s = pluralize!(span_len),
- are = pluralize!("is", span_len),
- ));
-
+ msg,
+ |err| {
if is_positional {
err.multipart_suggestion(
&format!(
@@ -800,7 +787,7 @@ impl<'tcx> DeadVisitor<'tcx> {
);
err.note(&msg);
}
- err.emit();
+ err
},
);
}
@@ -874,19 +861,19 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) {
let module_items = tcx.hir_module_items(module);
for item in module_items.items() {
- if !live_symbols.contains(&item.def_id) {
- let parent = tcx.local_parent(item.def_id);
+ if !live_symbols.contains(&item.owner_id.def_id) {
+ let parent = tcx.local_parent(item.owner_id.def_id);
if parent != module && !live_symbols.contains(&parent) {
// We already have diagnosed something.
continue;
}
- visitor.check_definition(item.def_id);
+ visitor.check_definition(item.owner_id.def_id);
continue;
}
- let def_kind = tcx.def_kind(item.def_id);
+ let def_kind = tcx.def_kind(item.owner_id);
if let DefKind::Struct | DefKind::Union | DefKind::Enum = def_kind {
- let adt = tcx.adt_def(item.def_id);
+ let adt = tcx.adt_def(item.owner_id);
let mut dead_variants = Vec::new();
for variant in adt.variants() {
@@ -929,16 +916,21 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) {
visitor.warn_dead_fields_and_variants(def_id, "read", dead_fields, is_positional)
}
- visitor.warn_dead_fields_and_variants(item.def_id, "constructed", dead_variants, false);
+ visitor.warn_dead_fields_and_variants(
+ item.owner_id.def_id,
+ "constructed",
+ dead_variants,
+ false,
+ );
}
}
for impl_item in module_items.impl_items() {
- visitor.check_definition(impl_item.def_id);
+ visitor.check_definition(impl_item.owner_id.def_id);
}
for foreign_item in module_items.foreign_items() {
- visitor.check_definition(foreign_item.def_id);
+ visitor.check_definition(foreign_item.owner_id.def_id);
}
// We do not warn trait items.
diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
index e08683fe2..253b0a88e 100644
--- a/compiler/rustc_passes/src/debugger_visualizer.rs
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -13,6 +13,8 @@ use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
use std::sync::Arc;
+use crate::errors::DebugVisualizerUnreadable;
+
fn check_for_debugger_visualizer<'tcx>(
tcx: TyCtxt<'tcx>,
hir_id: HirId,
@@ -54,13 +56,12 @@ fn check_for_debugger_visualizer<'tcx>(
debugger_visualizers
.insert(DebuggerVisualizerFile::new(Arc::from(contents), visualizer_type));
}
- Err(err) => {
- tcx.sess
- .struct_span_err(
- meta_item.span,
- &format!("couldn't read {}: {}", file.display(), err),
- )
- .emit();
+ Err(error) => {
+ tcx.sess.emit_err(DebugVisualizerUnreadable {
+ span: meta_item.span,
+ file: &file,
+ error,
+ });
}
}
}
diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index e6b69d898..a72056e00 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -14,7 +14,9 @@ use rustc_hir::diagnostic_items::DiagnosticItems;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::{kw::Empty, sym, Symbol};
+
+use crate::errors::{DuplicateDiagnosticItem, DuplicateDiagnosticItemInCrate};
fn observe_item<'tcx>(
tcx: TyCtxt<'tcx>,
@@ -33,25 +35,22 @@ fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item
items.id_to_name.insert(item_def_id, name);
if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) {
if original_def_id != item_def_id {
- let mut err = match tcx.hir().span_if_local(item_def_id) {
- Some(span) => tcx
- .sess
- .struct_span_err(span, &format!("duplicate diagnostic item found: `{name}`.")),
- None => tcx.sess.struct_err(&format!(
- "duplicate diagnostic item in crate `{}`: `{}`.",
- tcx.crate_name(item_def_id.krate),
- name
- )),
- };
- if let Some(span) = tcx.hir().span_if_local(original_def_id) {
- err.span_note(span, "the diagnostic item is first defined here");
+ let orig_span = tcx.hir().span_if_local(original_def_id);
+ let orig_crate_name = if orig_span.is_some() {
+ None
} else {
- err.note(&format!(
- "the diagnostic item is first defined in crate `{}`.",
- tcx.crate_name(original_def_id.krate)
- ));
- }
- err.emit();
+ Some(tcx.crate_name(original_def_id.krate))
+ };
+ match tcx.hir().span_if_local(item_def_id) {
+ Some(span) => tcx.sess.emit_err(DuplicateDiagnosticItem { span, name }),
+ None => tcx.sess.emit_err(DuplicateDiagnosticItemInCrate {
+ span: orig_span,
+ orig_crate_name: orig_crate_name.unwrap_or(Empty),
+ have_orig_crate_name: orig_crate_name.map(|_| ()),
+ crate_name: tcx.crate_name(item_def_id.krate),
+ name,
+ }),
+ };
}
}
}
@@ -74,19 +73,19 @@ fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> DiagnosticItems
let crate_items = tcx.hir_crate_items(());
for id in crate_items.items() {
- observe_item(tcx, &mut diagnostic_items, id.def_id);
+ observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
}
for id in crate_items.trait_items() {
- observe_item(tcx, &mut diagnostic_items, id.def_id);
+ observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
}
for id in crate_items.impl_items() {
- observe_item(tcx, &mut diagnostic_items, id.def_id);
+ observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
}
for id in crate_items.foreign_items() {
- observe_item(tcx, &mut diagnostic_items, id.def_id);
+ observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
}
diagnostic_items
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index cd10170d3..5885f45ae 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -1,5 +1,5 @@
use rustc_ast::entry::EntryPointType;
-use rustc_errors::struct_span_err;
+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};
@@ -8,7 +8,12 @@ use rustc_middle::ty::{DefIdTree, TyCtxt};
use rustc_session::config::{sigpipe, CrateType, EntryFnType};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
-use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_span::{Span, Symbol};
+
+use crate::errors::{
+ AttrOnlyInFunctions, AttrOnlyOnMain, AttrOnlyOnRootMain, ExternMain, MultipleRustcMain,
+ MultipleStartFunctions, NoMainErr, UnixSigpipeValues,
+};
struct EntryContext<'tcx> {
tcx: TyCtxt<'tcx>,
@@ -57,7 +62,7 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry
} else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
EntryPointType::RustcMainAttr
} else {
- if let Some(name) = ctxt.tcx.opt_item_name(id.def_id.to_def_id())
+ if let Some(name) = ctxt.tcx.opt_item_name(id.owner_id.to_def_id())
&& name == sym::main {
if at_root {
// This is a top-level function so can be `main`.
@@ -71,64 +76,57 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry
}
}
-fn err_if_attr_found(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol, details: &str) {
+fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option<Span> {
let attrs = ctxt.tcx.hir().attrs(id.hir_id());
- if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym) {
- ctxt.tcx
- .sess
- .struct_span_err(attr.span, &format!("`{}` attribute {}", sym, details))
- .emit();
- }
+ ctxt.tcx.sess.find_by_name(attrs, sym).map(|attr| attr.span)
}
fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
- let at_root = ctxt.tcx.opt_local_parent(id.def_id) == Some(CRATE_DEF_ID);
+ let at_root = ctxt.tcx.opt_local_parent(id.owner_id.def_id) == Some(CRATE_DEF_ID);
match entry_point_type(ctxt, id, at_root) {
EntryPointType::None => {
- err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on `fn main()`");
+ if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
+ ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
+ }
}
- _ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => {
- err_if_attr_found(ctxt, id, sym::start, "can only be used on functions");
- err_if_attr_found(ctxt, id, sym::rustc_main, "can only be used on functions");
+ _ if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) => {
+ for attr in [sym::start, sym::rustc_main] {
+ if let Some(span) = attr_span_by_symbol(ctxt, id, attr) {
+ ctxt.tcx.sess.emit_err(AttrOnlyInFunctions { span, attr });
+ }
+ }
}
EntryPointType::MainNamed => (),
EntryPointType::OtherMain => {
- err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on root `fn main()`");
- ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id));
+ if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
+ ctxt.tcx.sess.emit_err(AttrOnlyOnRootMain { span, attr: sym::unix_sigpipe });
+ }
+ ctxt.non_main_fns.push(ctxt.tcx.def_span(id.owner_id));
}
EntryPointType::RustcMainAttr => {
if ctxt.attr_main_fn.is_none() {
- ctxt.attr_main_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id())));
+ ctxt.attr_main_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
} else {
- struct_span_err!(
- ctxt.tcx.sess,
- ctxt.tcx.def_span(id.def_id.to_def_id()),
- E0137,
- "multiple functions with a `#[rustc_main]` attribute"
- )
- .span_label(
- ctxt.tcx.def_span(id.def_id.to_def_id()),
- "additional `#[rustc_main]` function",
- )
- .span_label(ctxt.attr_main_fn.unwrap().1, "first `#[rustc_main]` function")
- .emit();
+ ctxt.tcx.sess.emit_err(MultipleRustcMain {
+ span: ctxt.tcx.def_span(id.owner_id.to_def_id()),
+ first: ctxt.attr_main_fn.unwrap().1,
+ additional: ctxt.tcx.def_span(id.owner_id.to_def_id()),
+ });
}
}
EntryPointType::Start => {
- err_if_attr_found(ctxt, id, sym::unix_sigpipe, "can only be used on `fn main()`");
+ if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
+ ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
+ }
if ctxt.start_fn.is_none() {
- ctxt.start_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id())));
+ ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
} else {
- struct_span_err!(
- ctxt.tcx.sess,
- ctxt.tcx.def_span(id.def_id.to_def_id()),
- E0138,
- "multiple `start` functions"
- )
- .span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
- .span_label(ctxt.tcx.def_span(id.def_id.to_def_id()), "multiple `start` functions")
- .emit();
+ ctxt.tcx.sess.emit_err(MultipleStartFunctions {
+ span: ctxt.tcx.def_span(id.owner_id),
+ labeled: ctxt.tcx.def_span(id.owner_id.to_def_id()),
+ previous: ctxt.start_fn.unwrap().1,
+ });
}
}
}
@@ -144,12 +142,7 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId,
if let Some(main_def) = tcx.resolutions(()).main_def && let Some(def_id) = main_def.opt_fn_def_id() {
// non-local main imports are handled below
if let Some(def_id) = def_id.as_local() && matches!(tcx.hir().find_by_def_id(def_id), Some(Node::ForeignItem(_))) {
- tcx.sess
- .struct_span_err(
- tcx.def_span(def_id),
- "the `main` function cannot be declared in an `extern` block",
- )
- .emit();
+ tcx.sess.emit_err(ExternMain { span: tcx.def_span(def_id) });
return None;
}
@@ -182,12 +175,7 @@ fn sigpipe(tcx: TyCtxt<'_>, def_id: DefId) -> u8 {
sigpipe::DEFAULT
}
_ => {
- tcx.sess
- .struct_span_err(
- attr.span,
- "valid values for `#[unix_sigpipe = \"...\"]` are `inherit`, `sig_ign`, or `sig_dfl`",
- )
- .emit();
+ tcx.sess.emit_err(UnixSigpipeValues { span: attr.span });
sigpipe::DEFAULT
}
}
@@ -206,52 +194,29 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) {
}
// There is no main function.
- let mut err = struct_span_err!(
- tcx.sess,
- DUMMY_SP,
- E0601,
- "`main` function not found in crate `{}`",
- tcx.crate_name(LOCAL_CRATE)
- );
- let filename = &tcx.sess.local_crate_source_file;
- let note = if !visitor.non_main_fns.is_empty() {
- for &span in &visitor.non_main_fns {
- err.span_note(span, "here is a function named `main`");
- }
- err.note("you have one or more functions named `main` not defined at the crate level");
- err.help("consider moving the `main` function definitions");
- // There were some functions named `main` though. Try to give the user a hint.
- format!(
- "the main function must be defined at the crate level{}",
- filename.as_ref().map(|f| format!(" (in `{}`)", f.display())).unwrap_or_default()
- )
- } else if let Some(filename) = filename {
- format!("consider adding a `main` function to `{}`", filename.display())
- } else {
- String::from("consider adding a `main` function at the crate level")
- };
+ let mut has_filename = true;
+ let filename = tcx.sess.local_crate_source_file.clone().unwrap_or_else(|| {
+ has_filename = false;
+ Default::default()
+ });
+ let main_def_opt = tcx.resolutions(()).main_def;
+ let diagnostic_id = error_code!(E0601);
+ let add_teach_note = tcx.sess.teach(&diagnostic_id);
// The file may be empty, which leads to the diagnostic machinery not emitting this
// note. This is a relatively simple way to detect that case and emit a span-less
// note instead.
- if tcx.sess.source_map().lookup_line(sp.hi()).is_ok() {
- err.set_span(sp.shrink_to_hi());
- err.span_label(sp.shrink_to_hi(), &note);
- } else {
- err.note(&note);
- }
-
- if let Some(main_def) = tcx.resolutions(()).main_def && main_def.opt_fn_def_id().is_none(){
- // There is something at `crate::main`, but it is not a function definition.
- err.span_label(main_def.span, "non-function item at `crate::main` is found");
- }
-
- if tcx.sess.teach(&err.get_code().unwrap()) {
- err.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/",
- );
- }
- err.emit();
+ let file_empty = !tcx.sess.source_map().lookup_line(sp.hi()).is_ok();
+
+ tcx.sess.emit_err(NoMainErr {
+ sp,
+ crate_name: tcx.crate_name(LOCAL_CRATE),
+ has_filename,
+ filename,
+ file_empty,
+ non_main_fns: visitor.non_main_fns.clone(),
+ main_def_opt,
+ add_teach_note,
+ });
}
pub fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 96cc8ae98..adaaf5392 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1,39 +1,49 @@
-use rustc_errors::{Applicability, MultiSpan};
-use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
-use rustc_span::{Span, Symbol};
+use std::{
+ io::Error,
+ path::{Path, PathBuf},
+};
+
+use rustc_ast::Label;
+use rustc_errors::{error_code, Applicability, ErrorGuaranteed, IntoDiagnostic, MultiSpan};
+use rustc_hir::{self as hir, ExprKind, Target};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
+use rustc_middle::ty::{MainDefinition, Ty};
+use rustc_span::{Span, Symbol, DUMMY_SP};
+
+use crate::lang_items::Duplicate;
#[derive(LintDiagnostic)]
-#[diag(passes::outer_crate_level_attr)]
+#[diag(passes_outer_crate_level_attr)]
pub struct OuterCrateLevelAttr;
#[derive(LintDiagnostic)]
-#[diag(passes::inner_crate_level_attr)]
+#[diag(passes_inner_crate_level_attr)]
pub struct InnerCrateLevelAttr;
#[derive(LintDiagnostic)]
-#[diag(passes::ignored_attr_with_macro)]
+#[diag(passes_ignored_attr_with_macro)]
pub struct IgnoredAttrWithMacro<'a> {
pub sym: &'a str,
}
#[derive(LintDiagnostic)]
-#[diag(passes::ignored_attr)]
+#[diag(passes_ignored_attr)]
pub struct IgnoredAttr<'a> {
pub sym: &'a str,
}
#[derive(LintDiagnostic)]
-#[diag(passes::inline_ignored_function_prototype)]
+#[diag(passes_inline_ignored_function_prototype)]
pub struct IgnoredInlineAttrFnProto;
#[derive(LintDiagnostic)]
-#[diag(passes::inline_ignored_constants)]
+#[diag(passes_inline_ignored_constants)]
#[warning]
#[note]
pub struct IgnoredInlineAttrConstants;
-#[derive(SessionDiagnostic)]
-#[diag(passes::inline_not_fn_or_closure, code = "E0518")]
+#[derive(Diagnostic)]
+#[diag(passes_inline_not_fn_or_closure, code = "E0518")]
pub struct InlineNotFnOrClosure {
#[primary_span]
pub attr_span: Span,
@@ -42,19 +52,19 @@ pub struct InlineNotFnOrClosure {
}
#[derive(LintDiagnostic)]
-#[diag(passes::no_coverage_ignored_function_prototype)]
+#[diag(passes_no_coverage_ignored_function_prototype)]
pub struct IgnoredNoCoverageFnProto;
#[derive(LintDiagnostic)]
-#[diag(passes::no_coverage_propagate)]
+#[diag(passes_no_coverage_propagate)]
pub struct IgnoredNoCoveragePropagate;
#[derive(LintDiagnostic)]
-#[diag(passes::no_coverage_fn_defn)]
+#[diag(passes_no_coverage_fn_defn)]
pub struct IgnoredNoCoverageFnDefn;
-#[derive(SessionDiagnostic)]
-#[diag(passes::no_coverage_not_coverable, code = "E0788")]
+#[derive(Diagnostic)]
+#[diag(passes_no_coverage_not_coverable, code = "E0788")]
pub struct IgnoredNoCoverageNotCoverable {
#[primary_span]
pub attr_span: Span,
@@ -62,8 +72,8 @@ pub struct IgnoredNoCoverageNotCoverable {
pub defn_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::should_be_applied_to_fn)]
+#[derive(Diagnostic)]
+#[diag(passes_should_be_applied_to_fn)]
pub struct AttrShouldBeAppliedToFn {
#[primary_span]
pub attr_span: Span,
@@ -71,15 +81,15 @@ pub struct AttrShouldBeAppliedToFn {
pub defn_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::naked_tracked_caller, code = "E0736")]
+#[derive(Diagnostic)]
+#[diag(passes_naked_tracked_caller, code = "E0736")]
pub struct NakedTrackedCaller {
#[primary_span]
pub attr_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::should_be_applied_to_fn, code = "E0739")]
+#[derive(Diagnostic)]
+#[diag(passes_should_be_applied_to_fn, code = "E0739")]
pub struct TrackedCallerWrongLocation {
#[primary_span]
pub attr_span: Span,
@@ -87,8 +97,8 @@ pub struct TrackedCallerWrongLocation {
pub defn_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::should_be_applied_to_struct_enum, code = "E0701")]
+#[derive(Diagnostic)]
+#[diag(passes_should_be_applied_to_struct_enum, code = "E0701")]
pub struct NonExhaustiveWrongLocation {
#[primary_span]
pub attr_span: Span,
@@ -96,8 +106,8 @@ pub struct NonExhaustiveWrongLocation {
pub defn_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::should_be_applied_to_trait)]
+#[derive(Diagnostic)]
+#[diag(passes_should_be_applied_to_trait)]
pub struct AttrShouldBeAppliedToTrait {
#[primary_span]
pub attr_span: Span,
@@ -106,11 +116,11 @@ pub struct AttrShouldBeAppliedToTrait {
}
#[derive(LintDiagnostic)]
-#[diag(passes::target_feature_on_statement)]
+#[diag(passes_target_feature_on_statement)]
pub struct TargetFeatureOnStatement;
-#[derive(SessionDiagnostic)]
-#[diag(passes::should_be_applied_to_static)]
+#[derive(Diagnostic)]
+#[diag(passes_should_be_applied_to_static)]
pub struct AttrShouldBeAppliedToStatic {
#[primary_span]
pub attr_span: Span,
@@ -118,24 +128,24 @@ pub struct AttrShouldBeAppliedToStatic {
pub defn_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::doc_expect_str)]
+#[derive(Diagnostic)]
+#[diag(passes_doc_expect_str)]
pub struct DocExpectStr<'a> {
#[primary_span]
pub attr_span: Span,
pub attr_name: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::doc_alias_empty)]
+#[derive(Diagnostic)]
+#[diag(passes_doc_alias_empty)]
pub struct DocAliasEmpty<'a> {
#[primary_span]
pub span: Span,
pub attr_str: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::doc_alias_bad_char)]
+#[derive(Diagnostic)]
+#[diag(passes_doc_alias_bad_char)]
pub struct DocAliasBadChar<'a> {
#[primary_span]
pub span: Span,
@@ -143,16 +153,16 @@ pub struct DocAliasBadChar<'a> {
pub char_: char,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::doc_alias_start_end)]
+#[derive(Diagnostic)]
+#[diag(passes_doc_alias_start_end)]
pub struct DocAliasStartEnd<'a> {
#[primary_span]
pub span: Span,
pub attr_str: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::doc_alias_bad_location)]
+#[derive(Diagnostic)]
+#[diag(passes_doc_alias_bad_location)]
pub struct DocAliasBadLocation<'a> {
#[primary_span]
pub span: Span,
@@ -160,8 +170,8 @@ pub struct DocAliasBadLocation<'a> {
pub location: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::doc_alias_not_an_alias)]
+#[derive(Diagnostic)]
+#[diag(passes_doc_alias_not_an_alias)]
pub struct DocAliasNotAnAlias<'a> {
#[primary_span]
pub span: Span,
@@ -169,64 +179,64 @@ pub struct DocAliasNotAnAlias<'a> {
}
#[derive(LintDiagnostic)]
-#[diag(passes::doc_alias_duplicated)]
+#[diag(passes_doc_alias_duplicated)]
pub struct DocAliasDuplicated {
#[label]
pub first_defn: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::doc_alias_not_string_literal)]
+#[derive(Diagnostic)]
+#[diag(passes_doc_alias_not_string_literal)]
pub struct DocAliasNotStringLiteral {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::doc_alias_malformed)]
+#[derive(Diagnostic)]
+#[diag(passes_doc_alias_malformed)]
pub struct DocAliasMalformed {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::doc_keyword_empty_mod)]
+#[derive(Diagnostic)]
+#[diag(passes_doc_keyword_empty_mod)]
pub struct DocKeywordEmptyMod {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::doc_keyword_not_mod)]
+#[derive(Diagnostic)]
+#[diag(passes_doc_keyword_not_mod)]
pub struct DocKeywordNotMod {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::doc_keyword_invalid_ident)]
+#[derive(Diagnostic)]
+#[diag(passes_doc_keyword_invalid_ident)]
pub struct DocKeywordInvalidIdent {
#[primary_span]
pub span: Span,
pub doc_keyword: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::doc_fake_variadic_not_valid)]
+#[derive(Diagnostic)]
+#[diag(passes_doc_fake_variadic_not_valid)]
pub struct DocFakeVariadicNotValid {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::doc_keyword_only_impl)]
+#[derive(Diagnostic)]
+#[diag(passes_doc_keyword_only_impl)]
pub struct DocKeywordOnlyImpl {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::doc_inline_conflict)]
+#[derive(Diagnostic)]
+#[diag(passes_doc_inline_conflict)]
#[help]
pub struct DocKeywordConflict {
#[primary_span]
@@ -234,17 +244,17 @@ pub struct DocKeywordConflict {
}
#[derive(LintDiagnostic)]
-#[diag(passes::doc_inline_only_use)]
+#[diag(passes_doc_inline_only_use)]
#[note]
pub struct DocInlineOnlyUse {
#[label]
pub attr_span: Span,
- #[label(passes::not_a_use_item_label)]
+ #[label(not_a_use_item_label)]
pub item_span: Option<Span>,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::doc_attr_not_crate_level)]
+#[derive(Diagnostic)]
+#[diag(passes_doc_attr_not_crate_level)]
pub struct DocAttrNotCrateLevel<'a> {
#[primary_span]
pub span: Span,
@@ -252,29 +262,33 @@ pub struct DocAttrNotCrateLevel<'a> {
}
#[derive(LintDiagnostic)]
-#[diag(passes::doc_test_unknown)]
+#[diag(passes_doc_test_unknown)]
pub struct DocTestUnknown {
pub path: String,
}
#[derive(LintDiagnostic)]
-#[diag(passes::doc_test_takes_list)]
+#[diag(passes_doc_test_takes_list)]
pub struct DocTestTakesList;
#[derive(LintDiagnostic)]
-#[diag(passes::doc_primitive)]
+#[diag(passes_doc_cfg_hide_takes_list)]
+pub struct DocCfgHideTakesList;
+
+#[derive(LintDiagnostic)]
+#[diag(passes_doc_primitive)]
pub struct DocPrimitive;
#[derive(LintDiagnostic)]
-#[diag(passes::doc_test_unknown_any)]
+#[diag(passes_doc_test_unknown_any)]
pub struct DocTestUnknownAny {
pub path: String,
}
#[derive(LintDiagnostic)]
-#[diag(passes::doc_test_unknown_spotlight)]
+#[diag(passes_doc_test_unknown_spotlight)]
#[note]
-#[note(passes::no_op_note)]
+#[note(no_op_note)]
pub struct DocTestUnknownSpotlight {
pub path: String,
#[suggestion_short(applicability = "machine-applicable", code = "notable_trait")]
@@ -282,7 +296,7 @@ pub struct DocTestUnknownSpotlight {
}
#[derive(LintDiagnostic)]
-#[diag(passes::doc_test_unknown_include)]
+#[diag(passes_doc_test_unknown_include)]
pub struct DocTestUnknownInclude {
pub path: String,
pub value: String,
@@ -292,11 +306,11 @@ pub struct DocTestUnknownInclude {
}
#[derive(LintDiagnostic)]
-#[diag(passes::doc_invalid)]
+#[diag(passes_doc_invalid)]
pub struct DocInvalid;
-#[derive(SessionDiagnostic)]
-#[diag(passes::pass_by_value)]
+#[derive(Diagnostic)]
+#[diag(passes_pass_by_value)]
pub struct PassByValue {
#[primary_span]
pub attr_span: Span,
@@ -304,8 +318,8 @@ pub struct PassByValue {
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::allow_incoherent_impl)]
+#[derive(Diagnostic)]
+#[diag(passes_allow_incoherent_impl)]
pub struct AllowIncoherentImpl {
#[primary_span]
pub attr_span: Span,
@@ -313,8 +327,8 @@ pub struct AllowIncoherentImpl {
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::has_incoherent_inherent_impl)]
+#[derive(Diagnostic)]
+#[diag(passes_has_incoherent_inherent_impl)]
pub struct HasIncoherentInherentImpl {
#[primary_span]
pub attr_span: Span,
@@ -323,21 +337,21 @@ pub struct HasIncoherentInherentImpl {
}
#[derive(LintDiagnostic)]
-#[diag(passes::must_use_async)]
+#[diag(passes_must_use_async)]
pub struct MustUseAsync {
#[label]
pub span: Span,
}
#[derive(LintDiagnostic)]
-#[diag(passes::must_use_no_effect)]
+#[diag(passes_must_use_no_effect)]
pub struct MustUseNoEffect {
pub article: &'static str,
pub target: rustc_hir::Target,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::must_not_suspend)]
+#[derive(Diagnostic)]
+#[diag(passes_must_not_suspend)]
pub struct MustNotSuspend {
#[primary_span]
pub attr_span: Span,
@@ -346,7 +360,7 @@ pub struct MustNotSuspend {
}
#[derive(LintDiagnostic)]
-#[diag(passes::cold)]
+#[diag(passes_cold)]
#[warning]
pub struct Cold {
#[label]
@@ -354,7 +368,7 @@ pub struct Cold {
}
#[derive(LintDiagnostic)]
-#[diag(passes::link)]
+#[diag(passes_link)]
#[warning]
pub struct Link {
#[label]
@@ -362,7 +376,7 @@ pub struct Link {
}
#[derive(LintDiagnostic)]
-#[diag(passes::link_name)]
+#[diag(passes_link_name)]
#[warning]
pub struct LinkName<'a> {
#[help]
@@ -372,8 +386,8 @@ pub struct LinkName<'a> {
pub value: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::no_link)]
+#[derive(Diagnostic)]
+#[diag(passes_no_link)]
pub struct NoLink {
#[primary_span]
pub attr_span: Span,
@@ -381,8 +395,8 @@ pub struct NoLink {
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::export_name)]
+#[derive(Diagnostic)]
+#[diag(passes_export_name)]
pub struct ExportName {
#[primary_span]
pub attr_span: Span,
@@ -390,8 +404,8 @@ pub struct ExportName {
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::rustc_layout_scalar_valid_range_not_struct)]
+#[derive(Diagnostic)]
+#[diag(passes_rustc_layout_scalar_valid_range_not_struct)]
pub struct RustcLayoutScalarValidRangeNotStruct {
#[primary_span]
pub attr_span: Span,
@@ -399,15 +413,15 @@ pub struct RustcLayoutScalarValidRangeNotStruct {
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::rustc_layout_scalar_valid_range_arg)]
+#[derive(Diagnostic)]
+#[diag(passes_rustc_layout_scalar_valid_range_arg)]
pub struct RustcLayoutScalarValidRangeArg {
#[primary_span]
pub attr_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::rustc_legacy_const_generics_only)]
+#[derive(Diagnostic)]
+#[diag(passes_rustc_legacy_const_generics_only)]
pub struct RustcLegacyConstGenericsOnly {
#[primary_span]
pub attr_span: Span,
@@ -415,8 +429,8 @@ pub struct RustcLegacyConstGenericsOnly {
pub param_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::rustc_legacy_const_generics_index)]
+#[derive(Diagnostic)]
+#[diag(passes_rustc_legacy_const_generics_index)]
pub struct RustcLegacyConstGenericsIndex {
#[primary_span]
pub attr_span: Span,
@@ -424,8 +438,8 @@ pub struct RustcLegacyConstGenericsIndex {
pub generics_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::rustc_legacy_const_generics_index_exceed)]
+#[derive(Diagnostic)]
+#[diag(passes_rustc_legacy_const_generics_index_exceed)]
pub struct RustcLegacyConstGenericsIndexExceed {
#[primary_span]
#[label]
@@ -433,22 +447,22 @@ pub struct RustcLegacyConstGenericsIndexExceed {
pub arg_count: usize,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::rustc_legacy_const_generics_index_negative)]
+#[derive(Diagnostic)]
+#[diag(passes_rustc_legacy_const_generics_index_negative)]
pub struct RustcLegacyConstGenericsIndexNegative {
#[primary_span]
pub invalid_args: Vec<Span>,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::rustc_dirty_clean)]
+#[derive(Diagnostic)]
+#[diag(passes_rustc_dirty_clean)]
pub struct RustcDirtyClean {
#[primary_span]
pub span: Span,
}
#[derive(LintDiagnostic)]
-#[diag(passes::link_section)]
+#[diag(passes_link_section)]
#[warning]
pub struct LinkSection {
#[label]
@@ -456,52 +470,52 @@ pub struct LinkSection {
}
#[derive(LintDiagnostic)]
-#[diag(passes::no_mangle_foreign)]
+#[diag(passes_no_mangle_foreign)]
#[warning]
#[note]
pub struct NoMangleForeign {
#[label]
pub span: Span,
- #[suggestion(applicability = "machine-applicable")]
+ #[suggestion(code = "", applicability = "machine-applicable")]
pub attr_span: Span,
pub foreign_item_kind: &'static str,
}
#[derive(LintDiagnostic)]
-#[diag(passes::no_mangle)]
+#[diag(passes_no_mangle)]
#[warning]
pub struct NoMangle {
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::repr_ident, code = "E0565")]
+#[derive(Diagnostic)]
+#[diag(passes_repr_ident, code = "E0565")]
pub struct ReprIdent {
#[primary_span]
pub span: Span,
}
#[derive(LintDiagnostic)]
-#[diag(passes::repr_conflicting, code = "E0566")]
+#[diag(passes_repr_conflicting, code = "E0566")]
pub struct ReprConflicting;
-#[derive(SessionDiagnostic)]
-#[diag(passes::used_static)]
+#[derive(Diagnostic)]
+#[diag(passes_used_static)]
pub struct UsedStatic {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::used_compiler_linker)]
+#[derive(Diagnostic)]
+#[diag(passes_used_compiler_linker)]
pub struct UsedCompilerLinker {
#[primary_span]
pub spans: Vec<Span>,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::allow_internal_unstable)]
+#[derive(Diagnostic)]
+#[diag(passes_allow_internal_unstable)]
pub struct AllowInternalUnstable {
#[primary_span]
pub attr_span: Span,
@@ -509,25 +523,34 @@ pub struct AllowInternalUnstable {
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::debug_visualizer_placement)]
+#[derive(Diagnostic)]
+#[diag(passes_debug_visualizer_placement)]
pub struct DebugVisualizerPlacement {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::debug_visualizer_invalid)]
-#[note(passes::note_1)]
-#[note(passes::note_2)]
-#[note(passes::note_3)]
+#[derive(Diagnostic)]
+#[diag(passes_debug_visualizer_invalid)]
+#[note(note_1)]
+#[note(note_2)]
+#[note(note_3)]
pub struct DebugVisualizerInvalid {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::rustc_allow_const_fn_unstable)]
+#[derive(Diagnostic)]
+#[diag(passes_debug_visualizer_unreadable)]
+pub struct DebugVisualizerUnreadable<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub file: &'a Path,
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_rustc_allow_const_fn_unstable)]
pub struct RustcAllowConstFnUnstable {
#[primary_span]
pub attr_span: Span,
@@ -535,8 +558,8 @@ pub struct RustcAllowConstFnUnstable {
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::rustc_std_internal_symbol)]
+#[derive(Diagnostic)]
+#[diag(passes_rustc_std_internal_symbol)]
pub struct RustcStdInternalSymbol {
#[primary_span]
pub attr_span: Span,
@@ -544,66 +567,66 @@ pub struct RustcStdInternalSymbol {
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::const_trait)]
+#[derive(Diagnostic)]
+#[diag(passes_const_trait)]
pub struct ConstTrait {
#[primary_span]
pub attr_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::link_ordinal)]
+#[derive(Diagnostic)]
+#[diag(passes_link_ordinal)]
pub struct LinkOrdinal {
#[primary_span]
pub attr_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::stability_promotable)]
+#[derive(Diagnostic)]
+#[diag(passes_stability_promotable)]
pub struct StabilityPromotable {
#[primary_span]
pub attr_span: Span,
}
#[derive(LintDiagnostic)]
-#[diag(passes::deprecated)]
+#[diag(passes_deprecated)]
pub struct Deprecated;
#[derive(LintDiagnostic)]
-#[diag(passes::macro_use)]
+#[diag(passes_macro_use)]
pub struct MacroUse {
pub name: Symbol,
}
#[derive(LintDiagnostic)]
-#[diag(passes::macro_export)]
+#[diag(passes_macro_export)]
pub struct MacroExport;
#[derive(LintDiagnostic)]
-#[diag(passes::plugin_registrar)]
+#[diag(passes_plugin_registrar)]
pub struct PluginRegistrar;
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub enum UnusedNote {
- #[note(passes::unused_empty_lints_note)]
+ #[note(passes_unused_empty_lints_note)]
EmptyList { name: Symbol },
- #[note(passes::unused_no_lints_note)]
+ #[note(passes_unused_no_lints_note)]
NoLints { name: Symbol },
- #[note(passes::unused_default_method_body_const_note)]
+ #[note(passes_unused_default_method_body_const_note)]
DefaultMethodBodyConst,
}
#[derive(LintDiagnostic)]
-#[diag(passes::unused)]
+#[diag(passes_unused)]
pub struct Unused {
- #[suggestion(applicability = "machine-applicable")]
+ #[suggestion(code = "", applicability = "machine-applicable")]
pub attr_span: Span,
#[subdiagnostic]
pub note: UnusedNote,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::non_exported_macro_invalid_attrs, code = "E0518")]
+#[derive(Diagnostic)]
+#[diag(passes_non_exported_macro_invalid_attrs, code = "E0518")]
pub struct NonExportedMacroInvalidAttrs {
#[primary_span]
#[label]
@@ -611,7 +634,7 @@ pub struct NonExportedMacroInvalidAttrs {
}
#[derive(LintDiagnostic)]
-#[diag(passes::unused_duplicate)]
+#[diag(passes_unused_duplicate)]
pub struct UnusedDuplicate {
#[suggestion(code = "", applicability = "machine-applicable")]
pub this: Span,
@@ -621,8 +644,8 @@ pub struct UnusedDuplicate {
pub warning: Option<()>,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::unused_multiple)]
+#[derive(Diagnostic)]
+#[diag(passes_unused_multiple)]
pub struct UnusedMultiple {
#[primary_span]
#[suggestion(code = "", applicability = "machine-applicable")]
@@ -632,8 +655,8 @@ pub struct UnusedMultiple {
pub name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::rustc_lint_opt_ty)]
+#[derive(Diagnostic)]
+#[diag(passes_rustc_lint_opt_ty)]
pub struct RustcLintOptTy {
#[primary_span]
pub attr_span: Span,
@@ -641,8 +664,8 @@ pub struct RustcLintOptTy {
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::rustc_lint_opt_deny_field_access)]
+#[derive(Diagnostic)]
+#[diag(passes_rustc_lint_opt_deny_field_access)]
pub struct RustcLintOptDenyFieldAccess {
#[primary_span]
pub attr_span: Span,
@@ -650,11 +673,779 @@ pub struct RustcLintOptDenyFieldAccess {
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(passes::collapse_debuginfo)]
+#[derive(Diagnostic)]
+#[diag(passes_collapse_debuginfo)]
pub struct CollapseDebuginfo {
#[primary_span]
pub attr_span: Span,
#[label]
pub defn_span: Span,
}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_deprecated_annotation_has_no_effect)]
+pub struct DeprecatedAnnotationHasNoEffect {
+ #[suggestion(applicability = "machine-applicable", code = "")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_unknown_external_lang_item, code = "E0264")]
+pub struct UnknownExternLangItem {
+ #[primary_span]
+ pub span: Span,
+ pub lang_item: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_missing_panic_handler)]
+pub struct MissingPanicHandler;
+
+#[derive(Diagnostic)]
+#[diag(passes_alloc_func_required)]
+pub struct AllocFuncRequired;
+
+#[derive(Diagnostic)]
+#[diag(passes_missing_alloc_error_handler)]
+pub struct MissingAllocErrorHandler;
+
+#[derive(Diagnostic)]
+#[diag(passes_missing_lang_item)]
+#[note]
+#[help]
+pub struct MissingLangItem {
+ pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_lang_item_on_incorrect_target, code = "E0718")]
+pub struct LangItemOnIncorrectTarget {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub name: Symbol,
+ pub expected_target: Target,
+ pub actual_target: Target,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_unknown_lang_item, code = "E0522")]
+pub struct UnknownLangItem {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub name: Symbol,
+}
+
+pub struct InvalidAttrAtCrateLevel {
+ pub span: Span,
+ pub snippet: Option<String>,
+ pub name: Symbol,
+}
+
+impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
+ fn into_diagnostic(
+ self,
+ handler: &'_ rustc_errors::Handler,
+ ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+ let mut diag = handler.struct_err(rustc_errors::fluent::passes_invalid_attr_at_crate_level);
+ diag.set_span(self.span);
+ diag.set_arg("name", self.name);
+ // Only emit an error with a suggestion if we can create a string out
+ // of the attribute span
+ if let Some(src) = self.snippet {
+ let replacement = src.replace("#!", "#");
+ diag.span_suggestion_verbose(
+ self.span,
+ rustc_errors::fluent::suggestion,
+ replacement,
+ rustc_errors::Applicability::MachineApplicable,
+ );
+ }
+ diag
+ }
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_duplicate_diagnostic_item)]
+pub struct DuplicateDiagnosticItem {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_duplicate_diagnostic_item_in_crate)]
+pub struct DuplicateDiagnosticItemInCrate {
+ #[note(passes_diagnostic_item_first_defined)]
+ pub span: Option<Span>,
+ pub orig_crate_name: Symbol,
+ #[note]
+ pub have_orig_crate_name: Option<()>,
+ pub crate_name: Symbol,
+ pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_abi)]
+pub struct Abi {
+ #[primary_span]
+ pub span: Span,
+ pub abi: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_align)]
+pub struct Align {
+ #[primary_span]
+ pub span: Span,
+ pub align: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_size)]
+pub struct Size {
+ #[primary_span]
+ pub span: Span,
+ pub size: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_homogeneous_aggregate)]
+pub struct HomogeneousAggregate {
+ #[primary_span]
+ pub span: Span,
+ pub homogeneous_aggregate: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_layout_of)]
+pub struct LayoutOf {
+ #[primary_span]
+ pub span: Span,
+ pub normalized_ty: String,
+ pub ty_layout: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_unrecognized_field)]
+pub struct UnrecognizedField {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_feature_stable_twice, code = "E0711")]
+pub struct FeatureStableTwice {
+ #[primary_span]
+ pub span: Span,
+ pub feature: Symbol,
+ pub since: Symbol,
+ pub prev_since: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_feature_previously_declared, code = "E0711")]
+pub struct FeaturePreviouslyDeclared<'a, 'b> {
+ #[primary_span]
+ pub span: Span,
+ pub feature: Symbol,
+ pub declared: &'a str,
+ pub prev_declared: &'b str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_expr_not_allowed_in_context, code = "E0744")]
+pub struct ExprNotAllowedInContext<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub expr: String,
+ pub context: &'a str,
+}
+
+pub struct BreakNonLoop<'a> {
+ pub span: Span,
+ pub head: Option<Span>,
+ pub kind: &'a str,
+ pub suggestion: String,
+ pub loop_label: Option<Label>,
+ pub break_label: Option<Label>,
+ pub break_expr_kind: &'a ExprKind<'a>,
+ pub break_expr_span: Span,
+}
+
+impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> {
+ fn into_diagnostic(
+ self,
+ handler: &rustc_errors::Handler,
+ ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+ let mut diag = handler.struct_span_err_with_code(
+ self.span,
+ rustc_errors::fluent::passes_break_non_loop,
+ error_code!(E0571),
+ );
+ diag.set_arg("kind", self.kind);
+ diag.span_label(self.span, rustc_errors::fluent::label);
+ if let Some(head) = self.head {
+ diag.span_label(head, rustc_errors::fluent::label2);
+ }
+ diag.span_suggestion(
+ self.span,
+ rustc_errors::fluent::suggestion,
+ self.suggestion,
+ Applicability::MaybeIncorrect,
+ );
+ if let (Some(label), None) = (self.loop_label, self.break_label) {
+ match self.break_expr_kind {
+ ExprKind::Path(hir::QPath::Resolved(
+ None,
+ hir::Path { segments: [segment], res: hir::def::Res::Err, .. },
+ )) if label.ident.to_string() == format!("'{}", segment.ident) => {
+ // This error is redundant, we will have already emitted a
+ // suggestion to use the label when `segment` wasn't found
+ // (hence the `Res::Err` check).
+ diag.delay_as_bug();
+ }
+ _ => {
+ diag.span_suggestion(
+ self.break_expr_span,
+ rustc_errors::fluent::break_expr_suggestion,
+ label.ident,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ diag
+ }
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_continue_labeled_block, code = "E0696")]
+pub struct ContinueLabeledBlock {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[label(block_label)]
+ pub block_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_break_inside_closure, code = "E0267")]
+pub struct BreakInsideClosure<'a> {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[label(closure_label)]
+ pub closure_span: Span,
+ pub name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_break_inside_async_block, code = "E0267")]
+pub struct BreakInsideAsyncBlock<'a> {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[label(async_block_label)]
+ pub closure_span: Span,
+ pub name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_outside_loop, code = "E0268")]
+pub struct OutsideLoop<'a> {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_unlabeled_in_labeled_block, code = "E0695")]
+pub struct UnlabeledInLabeledBlock<'a> {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub cf_type: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_unlabeled_cf_in_while_condition, code = "E0590")]
+pub struct UnlabeledCfInWhileCondition<'a> {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub cf_type: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_cannot_inline_naked_function)]
+pub struct CannotInlineNakedFunction {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_undefined_naked_function_abi)]
+pub struct UndefinedNakedFunctionAbi;
+
+#[derive(Diagnostic)]
+#[diag(passes_no_patterns)]
+pub struct NoPatterns {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_params_not_allowed)]
+#[help]
+pub struct ParamsNotAllowed {
+ #[primary_span]
+ pub span: Span,
+}
+
+pub struct NakedFunctionsAsmBlock {
+ pub span: Span,
+ pub multiple_asms: Vec<Span>,
+ pub non_asms: Vec<Span>,
+}
+
+impl IntoDiagnostic<'_> for NakedFunctionsAsmBlock {
+ fn into_diagnostic(
+ self,
+ handler: &rustc_errors::Handler,
+ ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+ let mut diag = handler.struct_span_err_with_code(
+ self.span,
+ rustc_errors::fluent::passes_naked_functions_asm_block,
+ error_code!(E0787),
+ );
+ for span in self.multiple_asms.iter() {
+ diag.span_label(*span, rustc_errors::fluent::label_multiple_asm);
+ }
+ for span in self.non_asms.iter() {
+ diag.span_label(*span, rustc_errors::fluent::label_non_asm);
+ }
+ diag
+ }
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_naked_functions_operands, code = "E0787")]
+pub struct NakedFunctionsOperands {
+ #[primary_span]
+ pub unsupported_operands: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_naked_functions_asm_options, code = "E0787")]
+pub struct NakedFunctionsAsmOptions {
+ #[primary_span]
+ pub span: Span,
+ pub unsupported_options: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_naked_functions_must_use_noreturn, code = "E0787")]
+pub struct NakedFunctionsMustUseNoreturn {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(code = ", options(noreturn)", applicability = "machine-applicable")]
+ pub last_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_attr_only_on_main)]
+pub struct AttrOnlyOnMain {
+ #[primary_span]
+ pub span: Span,
+ pub attr: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_attr_only_on_root_main)]
+pub struct AttrOnlyOnRootMain {
+ #[primary_span]
+ pub span: Span,
+ pub attr: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_attr_only_in_functions)]
+pub struct AttrOnlyInFunctions {
+ #[primary_span]
+ pub span: Span,
+ pub attr: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_multiple_rustc_main, code = "E0137")]
+pub struct MultipleRustcMain {
+ #[primary_span]
+ pub span: Span,
+ #[label(first)]
+ pub first: Span,
+ #[label(additional)]
+ pub additional: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_multiple_start_functions, code = "E0138")]
+pub struct MultipleStartFunctions {
+ #[primary_span]
+ pub span: Span,
+ #[label]
+ pub labeled: Span,
+ #[label(previous)]
+ pub previous: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_extern_main)]
+pub struct ExternMain {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_unix_sigpipe_values)]
+pub struct UnixSigpipeValues {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_no_main_function, code = "E0601")]
+pub struct NoMainFunction {
+ #[primary_span]
+ pub span: Span,
+ pub crate_name: String,
+}
+
+pub struct NoMainErr {
+ pub sp: Span,
+ pub crate_name: Symbol,
+ pub has_filename: bool,
+ pub filename: PathBuf,
+ pub file_empty: bool,
+ pub non_main_fns: Vec<Span>,
+ pub main_def_opt: Option<MainDefinition>,
+ pub add_teach_note: bool,
+}
+
+impl<'a> IntoDiagnostic<'a> for NoMainErr {
+ fn into_diagnostic(
+ self,
+ handler: &'a rustc_errors::Handler,
+ ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
+ let mut diag = handler.struct_span_err_with_code(
+ DUMMY_SP,
+ rustc_errors::fluent::passes_no_main_function,
+ error_code!(E0601),
+ );
+ diag.set_arg("crate_name", self.crate_name);
+ diag.set_arg("filename", self.filename);
+ diag.set_arg("has_filename", self.has_filename);
+ let note = if !self.non_main_fns.is_empty() {
+ for &span in &self.non_main_fns {
+ diag.span_note(span, rustc_errors::fluent::here_is_main);
+ }
+ diag.note(rustc_errors::fluent::one_or_more_possible_main);
+ diag.help(rustc_errors::fluent::consider_moving_main);
+ // There were some functions named `main` though. Try to give the user a hint.
+ rustc_errors::fluent::main_must_be_defined_at_crate
+ } else if self.has_filename {
+ rustc_errors::fluent::consider_adding_main_to_file
+ } else {
+ rustc_errors::fluent::consider_adding_main_at_crate
+ };
+ if self.file_empty {
+ diag.note(note);
+ } else {
+ diag.set_span(self.sp.shrink_to_hi());
+ diag.span_label(self.sp.shrink_to_hi(), note);
+ }
+
+ if let Some(main_def) = self.main_def_opt && main_def.opt_fn_def_id().is_none(){
+ // There is something at `crate::main`, but it is not a function definition.
+ diag.span_label(main_def.span, rustc_errors::fluent::non_function_main);
+ }
+
+ if self.add_teach_note {
+ diag.note(rustc_errors::fluent::teach_note);
+ }
+ diag
+ }
+}
+
+pub struct DuplicateLangItem {
+ pub local_span: Option<Span>,
+ pub lang_item_name: Symbol,
+ pub crate_name: Symbol,
+ pub dependency_of: Symbol,
+ pub is_local: bool,
+ pub path: String,
+ pub first_defined_span: Option<Span>,
+ pub orig_crate_name: Symbol,
+ pub orig_dependency_of: Symbol,
+ pub orig_is_local: bool,
+ pub orig_path: String,
+ pub(crate) duplicate: Duplicate,
+}
+
+impl IntoDiagnostic<'_> for DuplicateLangItem {
+ fn into_diagnostic(
+ self,
+ handler: &rustc_errors::Handler,
+ ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
+ let mut diag = handler.struct_err_with_code(
+ match self.duplicate {
+ Duplicate::Plain => rustc_errors::fluent::passes_duplicate_lang_item,
+
+ Duplicate::Crate => rustc_errors::fluent::passes_duplicate_lang_item_crate,
+ Duplicate::CrateDepends => {
+ rustc_errors::fluent::passes_duplicate_lang_item_crate_depends
+ }
+ },
+ error_code!(E0152),
+ );
+ diag.set_arg("lang_item_name", self.lang_item_name);
+ diag.set_arg("crate_name", self.crate_name);
+ diag.set_arg("dependency_of", self.dependency_of);
+ diag.set_arg("path", self.path);
+ diag.set_arg("orig_crate_name", self.orig_crate_name);
+ diag.set_arg("orig_dependency_of", self.orig_dependency_of);
+ diag.set_arg("orig_path", self.orig_path);
+ if let Some(span) = self.local_span {
+ diag.set_span(span);
+ }
+ if let Some(span) = self.first_defined_span {
+ diag.span_note(span, rustc_errors::fluent::first_defined_span);
+ } else {
+ if self.orig_dependency_of.is_empty() {
+ diag.note(rustc_errors::fluent::first_defined_crate);
+ } else {
+ diag.note(rustc_errors::fluent::first_defined_crate_depends);
+ }
+
+ if self.orig_is_local {
+ diag.note(rustc_errors::fluent::first_definition_local);
+ } else {
+ diag.note(rustc_errors::fluent::first_definition_path);
+ }
+
+ if self.is_local {
+ diag.note(rustc_errors::fluent::second_definition_local);
+ } else {
+ diag.note(rustc_errors::fluent::second_definition_path);
+ }
+ }
+ diag
+ }
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_incorrect_target, code = "E0718")]
+pub struct IncorrectTarget<'a> {
+ #[primary_span]
+ pub span: Span,
+ #[label]
+ pub generics_span: Span,
+ pub name: &'a str, // cannot be symbol because it renders e.g. `r#fn` instead of `fn`
+ pub kind: &'static str,
+ pub num: usize,
+ pub actual_num: usize,
+ pub at_least: bool,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_useless_assignment)]
+pub struct UselessAssignment<'a> {
+ pub is_field_assign: bool,
+ pub ty: Ty<'a>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_only_has_effect_on)]
+pub struct OnlyHasEffectOn {
+ pub attr_name: Symbol,
+ pub target_name: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_object_lifetime_err)]
+pub struct ObjectLifetimeErr {
+ #[primary_span]
+ pub span: Span,
+ pub repr: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_unrecognized_repr_hint, code = "E0552")]
+#[help]
+pub struct UnrecognizedReprHint {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+pub enum AttrApplication {
+ #[diag(passes_attr_application_enum, code = "E0517")]
+ Enum {
+ #[primary_span]
+ hint_span: Span,
+ #[label]
+ span: Span,
+ },
+ #[diag(passes_attr_application_struct, code = "E0517")]
+ Struct {
+ #[primary_span]
+ hint_span: Span,
+ #[label]
+ span: Span,
+ },
+ #[diag(passes_attr_application_struct_union, code = "E0517")]
+ StructUnion {
+ #[primary_span]
+ hint_span: Span,
+ #[label]
+ span: Span,
+ },
+ #[diag(passes_attr_application_struct_enum_union, code = "E0517")]
+ StructEnumUnion {
+ #[primary_span]
+ hint_span: Span,
+ #[label]
+ span: Span,
+ },
+ #[diag(passes_attr_application_struct_enum_function_union, code = "E0517")]
+ StructEnumFunctionUnion {
+ #[primary_span]
+ hint_span: Span,
+ #[label]
+ span: Span,
+ },
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_transparent_incompatible, code = "E0692")]
+pub struct TransparentIncompatible {
+ #[primary_span]
+ pub hint_spans: Vec<Span>,
+ pub target: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_deprecated_attribute, code = "E0549")]
+pub struct DeprecatedAttribute {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_useless_stability)]
+pub struct UselessStability {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[label(item)]
+ pub item_sp: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_invalid_stability)]
+pub struct InvalidStability {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[label(item)]
+ pub item_sp: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_cannot_stabilize_deprecated)]
+pub struct CannotStabilizeDeprecated {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[label(item)]
+ pub item_sp: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_invalid_deprecation_version)]
+pub struct InvalidDeprecationVersion {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[label(item)]
+ pub item_sp: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_missing_stability_attr)]
+pub struct MissingStabilityAttr<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub descr: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_missing_const_stab_attr)]
+pub struct MissingConstStabAttr<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub descr: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_trait_impl_const_stable)]
+#[note]
+pub struct TraitImplConstStable {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_feature_only_on_nightly, code = "E0554")]
+pub struct FeatureOnlyOnNightly {
+ #[primary_span]
+ pub span: Span,
+ pub release_channel: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_unknown_feature, code = "E0635")]
+pub struct UnknownFeature {
+ #[primary_span]
+ pub span: Span,
+ pub feature: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_implied_feature_not_exist)]
+pub struct ImpliedFeatureNotExist {
+ #[primary_span]
+ pub span: Span,
+ pub feature: Symbol,
+ pub implied_by: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_duplicate_feature_err, code = "E0636")]
+pub struct DuplicateFeatureErr {
+ #[primary_span]
+ pub span: Span,
+ pub feature: Symbol,
+}
+#[derive(Diagnostic)]
+#[diag(passes_missing_const_err)]
+pub struct MissingConstErr {
+ #[primary_span]
+ #[help]
+ pub fn_sig_span: Span,
+ #[label]
+ pub const_span: Span,
+}
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index 3bb8c0bb4..88bb39deb 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -1,6 +1,5 @@
use rustc_data_structures::sync::Lock;
use rustc_hir as hir;
-use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::intravisit;
use rustc_hir::{HirId, ItemLocalId};
use rustc_index::bit_set::GrowableBitSet;
@@ -42,7 +41,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
struct HirIdValidator<'a, 'hir> {
hir_map: Map<'hir>,
- owner: Option<LocalDefId>,
+ owner: Option<hir::OwnerId>,
hir_ids_seen: GrowableBitSet<ItemLocalId>,
errors: &'a Lock<Vec<String>>,
}
@@ -63,12 +62,12 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> {
self.errors.lock().push(f());
}
- fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, owner: LocalDefId, walk: F) {
+ fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, owner: hir::OwnerId, walk: F) {
assert!(self.owner.is_none());
self.owner = Some(owner);
walk(self);
- if owner == CRATE_DEF_ID {
+ if owner == hir::CRATE_OWNER_ID {
return;
}
@@ -97,14 +96,14 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> {
missing_items.push(format!(
"[local_id: {}, owner: {}]",
local_id,
- self.hir_map.def_path(owner).to_string_no_crate_verbose()
+ self.hir_map.def_path(owner.def_id).to_string_no_crate_verbose()
));
}
self.error(|| {
format!(
"ItemLocalIds not assigned densely in {}. \
Max ItemLocalId = {}, missing IDs = {:#?}; seens IDs = {:#?}",
- self.hir_map.def_path(owner).to_string_no_crate_verbose(),
+ self.hir_map.def_path(owner.def_id).to_string_no_crate_verbose(),
max,
missing_items,
self.hir_ids_seen
@@ -127,7 +126,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
fn visit_item(&mut self, i: &'hir hir::Item<'hir>) {
let mut inner_visitor = self.new_visitor(self.hir_map);
- inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i));
+ inner_visitor.check(i.owner_id, |this| intravisit::walk_item(this, i));
}
fn visit_id(&mut self, hir_id: HirId) {
@@ -138,8 +137,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
format!(
"HirIdValidator: The recorded owner of {} is {} instead of {}",
self.hir_map.node_to_string(hir_id),
- self.hir_map.def_path(hir_id.owner).to_string_no_crate_verbose(),
- self.hir_map.def_path(owner).to_string_no_crate_verbose()
+ self.hir_map.def_path(hir_id.owner.def_id).to_string_no_crate_verbose(),
+ self.hir_map.def_path(owner.def_id).to_string_no_crate_verbose()
)
});
}
@@ -149,16 +148,16 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) {
let mut inner_visitor = self.new_visitor(self.hir_map);
- inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i));
+ inner_visitor.check(i.owner_id, |this| intravisit::walk_foreign_item(this, i));
}
fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) {
let mut inner_visitor = self.new_visitor(self.hir_map);
- inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i));
+ inner_visitor.check(i.owner_id, |this| intravisit::walk_trait_item(this, i));
}
fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) {
let mut inner_visitor = self.new_visitor(self.hir_map);
- inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i));
+ inner_visitor.check(i.owner_id, |this| intravisit::walk_impl_item(this, i));
}
}
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 0be2fc053..33220fd2b 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -391,7 +391,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) {
record_variants!(
(self, ii, ii.kind, Id::Node(ii.hir_id()), hir, ImplItem, ImplItemKind),
- [Const, Fn, TyAlias]
+ [Const, Fn, Type]
);
hir_visit::walk_impl_item(self, ii)
}
@@ -620,7 +620,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
record_variants!(
(self, i, i.kind, Id::None, ast, AssocItem, AssocItemKind),
- [Const, Fn, TyAlias, MacCall]
+ [Const, Fn, Type, MacCall]
);
ast_visit::walk_assoc_item(self, i, ctxt);
}
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 79900a90a..df811be2a 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -8,9 +8,11 @@
//! * Functions called by the compiler itself.
use crate::check_attr::target_from_impl_item;
+use crate::errors::{
+ DuplicateLangItem, IncorrectTarget, LangItemOnIncorrectTarget, UnknownLangItem,
+};
use crate::weak_lang_items;
-use rustc_errors::{pluralize, struct_span_err};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
@@ -18,10 +20,16 @@ use rustc_hir::lang_items::{extract, GenericRequirement, ITEM_REFS};
use rustc_hir::{HirId, LangItem, LanguageItems, Target};
use rustc_middle::ty::TyCtxt;
use rustc_session::cstore::ExternCrate;
-use rustc_span::Span;
+use rustc_span::{symbol::kw::Empty, Span};
use rustc_middle::ty::query::Providers;
+pub(crate) enum Duplicate {
+ Plain,
+ Crate,
+ CrateDepends,
+}
+
struct LanguageItemCollector<'tcx> {
items: LanguageItems,
tcx: TyCtxt<'tcx>,
@@ -34,42 +42,24 @@ impl<'tcx> LanguageItemCollector<'tcx> {
fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) {
let attrs = self.tcx.hir().attrs(hir_id);
- if let Some((value, span)) = extract(&attrs) {
- match ITEM_REFS.get(&value).cloned() {
+ if let Some((name, span)) = extract(&attrs) {
+ match ITEM_REFS.get(&name).cloned() {
// Known lang item with attribute on correct target.
Some((item_index, expected_target)) if actual_target == expected_target => {
self.collect_item_extended(item_index, hir_id, span);
}
// Known lang item with attribute on incorrect target.
Some((_, expected_target)) => {
- struct_span_err!(
- self.tcx.sess,
+ self.tcx.sess.emit_err(LangItemOnIncorrectTarget {
span,
- E0718,
- "`{}` language item must be applied to a {}",
- value,
+ name,
expected_target,
- )
- .span_label(
- span,
- format!(
- "attribute should be applied to a {}, not a {}",
- expected_target, actual_target,
- ),
- )
- .emit();
+ actual_target,
+ });
}
// Unknown lang item.
_ => {
- struct_span_err!(
- self.tcx.sess,
- span,
- E0522,
- "definition of an unknown language item: `{}`",
- value
- )
- .span_label(span, format!("definition of unknown language item `{}`", value))
- .emit();
+ self.tcx.sess.emit_err(UnknownLangItem { span, name });
}
}
}
@@ -79,74 +69,72 @@ impl<'tcx> LanguageItemCollector<'tcx> {
// Check for duplicates.
if let Some(original_def_id) = self.items.items[item_index] {
if original_def_id != item_def_id {
- let lang_item = LangItem::from_u32(item_index as u32).unwrap();
- let name = lang_item.name();
- let mut err = match self.tcx.hir().span_if_local(item_def_id) {
- Some(span) => struct_span_err!(
- self.tcx.sess,
- span,
- E0152,
- "found duplicate lang item `{}`",
- name
- ),
- None => match self.tcx.extern_crate(item_def_id) {
- Some(ExternCrate { dependency_of, .. }) => {
- self.tcx.sess.struct_err(&format!(
- "duplicate lang item in crate `{}` (which `{}` depends on): `{}`.",
- self.tcx.crate_name(item_def_id.krate),
- self.tcx.crate_name(*dependency_of),
- name
- ))
- }
- _ => self.tcx.sess.struct_err(&format!(
- "duplicate lang item in crate `{}`: `{}`.",
- self.tcx.crate_name(item_def_id.krate),
- name
- )),
- },
+ let local_span = self.tcx.hir().span_if_local(item_def_id);
+ let lang_item_name = LangItem::from_u32(item_index as u32).unwrap().name();
+ let crate_name = self.tcx.crate_name(item_def_id.krate);
+ let mut dependency_of = Empty;
+ let is_local = item_def_id.is_local();
+ let path = if is_local {
+ String::new()
+ } else {
+ self.tcx
+ .crate_extern_paths(item_def_id.krate)
+ .iter()
+ .map(|p| p.display().to_string())
+ .collect::<Vec<_>>()
+ .join(", ")
+ .into()
};
- if let Some(span) = self.tcx.hir().span_if_local(original_def_id) {
- err.span_note(span, "the lang item is first defined here");
+ let first_defined_span = self.tcx.hir().span_if_local(original_def_id);
+ let mut orig_crate_name = Empty;
+ let mut orig_dependency_of = Empty;
+ let orig_is_local = original_def_id.is_local();
+ let orig_path = if orig_is_local {
+ String::new()
} else {
- match self.tcx.extern_crate(original_def_id) {
- Some(ExternCrate { dependency_of, .. }) => {
- err.note(&format!(
- "the lang item is first defined in crate `{}` (which `{}` depends on)",
- self.tcx.crate_name(original_def_id.krate),
- self.tcx.crate_name(*dependency_of)
- ));
- }
- _ => {
- err.note(&format!(
- "the lang item is first defined in crate `{}`.",
- self.tcx.crate_name(original_def_id.krate)
- ));
- }
+ self.tcx
+ .crate_extern_paths(original_def_id.krate)
+ .iter()
+ .map(|p| p.display().to_string())
+ .collect::<Vec<_>>()
+ .join(", ")
+ .into()
+ };
+ if first_defined_span.is_none() {
+ orig_crate_name = self.tcx.crate_name(original_def_id.krate);
+ if let Some(ExternCrate { dependency_of: inner_dependency_of, .. }) =
+ self.tcx.extern_crate(original_def_id)
+ {
+ orig_dependency_of = self.tcx.crate_name(*inner_dependency_of);
}
- let mut note_def = |which, def_id: DefId| {
- let crate_name = self.tcx.crate_name(def_id.krate);
- let note = if def_id.is_local() {
- format!("{} definition in the local crate (`{}`)", which, crate_name)
- } else {
- let paths: Vec<_> = self
- .tcx
- .crate_extern_paths(def_id.krate)
- .iter()
- .map(|p| p.display().to_string())
- .collect();
- format!(
- "{} definition in `{}` loaded from {}",
- which,
- crate_name,
- paths.join(", ")
- )
- };
- err.note(&note);
- };
- note_def("first", original_def_id);
- note_def("second", item_def_id);
}
- err.emit();
+
+ let duplicate = if local_span.is_some() {
+ Duplicate::Plain
+ } else {
+ match self.tcx.extern_crate(item_def_id) {
+ Some(ExternCrate { dependency_of: inner_dependency_of, .. }) => {
+ dependency_of = self.tcx.crate_name(*inner_dependency_of);
+ Duplicate::CrateDepends
+ }
+ _ => Duplicate::Crate,
+ }
+ };
+
+ self.tcx.sess.emit_err(DuplicateLangItem {
+ local_span,
+ lang_item_name,
+ crate_name,
+ dependency_of,
+ is_local,
+ path,
+ first_defined_span,
+ orig_crate_name,
+ orig_dependency_of,
+ orig_is_local,
+ orig_path,
+ duplicate,
+ });
}
}
@@ -179,41 +167,30 @@ impl<'tcx> LanguageItemCollector<'tcx> {
None => (0, *item_span),
};
+ let mut at_least = false;
let required = match lang_item.required_generics() {
- GenericRequirement::Exact(num) if num != actual_num => {
- Some((format!("{}", num), pluralize!(num)))
- }
+ GenericRequirement::Exact(num) if num != actual_num => Some(num),
GenericRequirement::Minimum(num) if actual_num < num => {
- Some((format!("at least {}", num), pluralize!(num)))
- }
+ at_least = true;
+ Some(num)}
+ ,
// If the number matches, or there is no requirement, handle it normally
_ => None,
};
- if let Some((range_str, pluralized)) = required {
+ if let Some(num) = required {
// We are issuing E0718 "incorrect target" here, because while the
// item kind of the target is correct, the target is still wrong
// because of the wrong number of generic arguments.
- struct_span_err!(
- self.tcx.sess,
+ self.tcx.sess.emit_err(IncorrectTarget {
span,
- E0718,
- "`{}` language item must be applied to a {} with {} generic argument{}",
- name,
- kind.descr(),
- range_str,
- pluralized,
- )
- .span_label(
generics_span,
- format!(
- "this {} has {} generic argument{}",
- kind.descr(),
- actual_num,
- pluralize!(actual_num),
- ),
- )
- .emit();
+ name: name.as_str(),
+ kind: kind.descr(),
+ num,
+ actual_num,
+ at_least,
+ });
// return early to not collect the lang item
return;
@@ -240,9 +217,9 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems {
let crate_items = tcx.hir_crate_items(());
for id in crate_items.items() {
- collector.check_for_lang(Target::from_def_kind(tcx.def_kind(id.def_id)), id.hir_id());
+ collector.check_for_lang(Target::from_def_kind(tcx.def_kind(id.owner_id)), id.hir_id());
- if matches!(tcx.def_kind(id.def_id), DefKind::Enum) {
+ if matches!(tcx.def_kind(id.owner_id), DefKind::Enum) {
let item = tcx.hir().item(id);
if let hir::ItemKind::Enum(def, ..) = &item.kind {
for variant in def.variants {
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index fd03f6571..5322baee7 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -3,20 +3,23 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
+use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_target::abi::{HasDataLayout, TargetDataLayout};
+use crate::errors::{Abi, Align, HomogeneousAggregate, LayoutOf, Size, UnrecognizedField};
+
pub fn test_layout(tcx: TyCtxt<'_>) {
if tcx.features().rustc_attrs {
// if the `rustc_attrs` feature is not enabled, don't bother testing layout
for id in tcx.hir().items() {
if matches!(
- tcx.def_kind(id.def_id),
+ tcx.def_kind(id.owner_id),
DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
) {
- for attr in tcx.get_attrs(id.def_id.to_def_id(), sym::rustc_layout) {
- dump_layout_of(tcx, id.def_id, attr);
+ for attr in tcx.get_attrs(id.owner_id.to_def_id(), sym::rustc_layout) {
+ dump_layout_of(tcx, id.owner_id.def_id, attr);
}
}
}
@@ -35,62 +38,64 @@ fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attri
for meta_item in meta_items {
match meta_item.name_or_empty() {
sym::abi => {
- tcx.sess.span_err(
- tcx.def_span(item_def_id.to_def_id()),
- &format!("abi: {:?}", ty_layout.abi),
- );
+ tcx.sess.emit_err(Abi {
+ span: tcx.def_span(item_def_id.to_def_id()),
+ abi: format!("{:?}", ty_layout.abi),
+ });
}
sym::align => {
- tcx.sess.span_err(
- tcx.def_span(item_def_id.to_def_id()),
- &format!("align: {:?}", ty_layout.align),
- );
+ tcx.sess.emit_err(Align {
+ span: tcx.def_span(item_def_id.to_def_id()),
+ align: format!("{:?}", ty_layout.align),
+ });
}
sym::size => {
- tcx.sess.span_err(
- tcx.def_span(item_def_id.to_def_id()),
- &format!("size: {:?}", ty_layout.size),
- );
+ tcx.sess.emit_err(Size {
+ span: tcx.def_span(item_def_id.to_def_id()),
+ size: format!("{:?}", ty_layout.size),
+ });
}
sym::homogeneous_aggregate => {
- tcx.sess.span_err(
- tcx.def_span(item_def_id.to_def_id()),
- &format!(
- "homogeneous_aggregate: {:?}",
- ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
+ tcx.sess.emit_err(HomogeneousAggregate {
+ span: tcx.def_span(item_def_id.to_def_id()),
+ homogeneous_aggregate: format!(
+ "{:?}",
+ ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env })
),
- );
+ });
}
sym::debug => {
- let normalized_ty = tcx.normalize_erasing_regions(
- param_env.with_reveal_all_normalized(tcx),
- ty,
- );
- tcx.sess.span_err(
- tcx.def_span(item_def_id.to_def_id()),
- &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
+ let normalized_ty = format!(
+ "{:?}",
+ tcx.normalize_erasing_regions(
+ param_env.with_reveal_all_normalized(tcx),
+ ty,
+ )
);
+ let ty_layout = format!("{:#?}", *ty_layout);
+ tcx.sess.emit_err(LayoutOf {
+ span: tcx.def_span(item_def_id.to_def_id()),
+ normalized_ty,
+ ty_layout,
+ });
}
name => {
- tcx.sess.span_err(
- meta_item.span(),
- &format!("unrecognized field name `{}`", name),
- );
+ tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
}
}
}
}
Err(layout_error) => {
- tcx.sess.span_err(
- tcx.def_span(item_def_id.to_def_id()),
- &format!("layout error: {:?}", layout_error),
- );
+ tcx.sess.emit_fatal(Spanned {
+ node: layout_error,
+ span: tcx.def_span(item_def_id.to_def_id()),
+ });
}
}
}
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 39ebb8db2..15f60f626 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -5,10 +5,11 @@
//! This API is completely unstable and subject to change.
#![allow(rustc::potential_query_instability)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(iter_intersperse)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(map_try_insert)]
#![feature(min_specialization)]
#![feature(try_blocks)]
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index 04173c792..b5843c0ae 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -6,7 +6,6 @@
use rustc_ast::{Attribute, MetaItemKind};
use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER};
-use rustc_errors::struct_span_err;
use rustc_hir::intravisit::Visitor;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::lib_features::LibFeatures;
@@ -15,6 +14,8 @@ use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::Symbol;
use rustc_span::{sym, Span};
+use crate::errors::{FeaturePreviouslyDeclared, FeatureStableTwice};
+
fn new_lib_features() -> LibFeatures {
LibFeatures { stable: Default::default(), unstable: Default::default() }
}
@@ -92,14 +93,12 @@ impl<'tcx> LibFeatureCollector<'tcx> {
(Some(since), _, false) => {
if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) {
if *prev_since != since {
- self.span_feature_error(
+ self.tcx.sess.emit_err(FeatureStableTwice {
span,
- &format!(
- "feature `{}` is declared stable since {}, \
- but was previously declared stable since {}",
- feature, since, prev_since,
- ),
- );
+ feature,
+ since,
+ prev_since: *prev_since,
+ });
return;
}
}
@@ -110,22 +109,17 @@ impl<'tcx> LibFeatureCollector<'tcx> {
self.lib_features.unstable.insert(feature, span);
}
(Some(_), _, true) | (None, true, _) => {
- self.span_feature_error(
+ let declared = if since.is_some() { "stable" } else { "unstable" };
+ let prev_declared = if since.is_none() { "stable" } else { "unstable" };
+ self.tcx.sess.emit_err(FeaturePreviouslyDeclared {
span,
- &format!(
- "feature `{}` is declared {}, but was previously declared {}",
- feature,
- if since.is_some() { "stable" } else { "unstable" },
- if since.is_none() { "stable" } else { "unstable" },
- ),
- );
+ feature,
+ declared,
+ prev_declared,
+ });
}
}
}
-
- fn span_feature_error(&self, span: Span, msg: &str) {
- struct_span_err!(self.tcx.sess, span, E0711, "{}", &msg).emit();
- }
}
impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> {
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 6a4cd79cd..c6fe40f72 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -1319,14 +1319,14 @@ 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(
lint::builtin::UNREACHABLE_CODE,
expr_id,
expr_span,
- |lint| {
- let msg = format!("unreachable {}", descr);
- lint.build(&msg)
- .span_label(expr_span, &msg)
+ &msg,
+ |diag| {
+ diag.span_label(expr_span, &msg)
.span_label(orig_span, "any code following this expression is unreachable")
.span_note(
orig_span,
@@ -1335,7 +1335,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
orig_ty
),
)
- .emit();
},
);
}
@@ -1491,14 +1490,8 @@ impl<'tcx> Liveness<'_, 'tcx> {
lint::builtin::UNUSED_ASSIGNMENTS,
var_hir_id,
vec![span],
- |lint| {
- lint.build(&format!(
- "value captured by `{}` is never read",
- name
- ))
- .help("did you mean to capture by reference instead?")
- .emit();
- },
+ format!("value captured by `{}` is never read", name),
+ |lint| lint.help("did you mean to capture by reference instead?"),
);
}
}
@@ -1508,11 +1501,8 @@ impl<'tcx> Liveness<'_, 'tcx> {
lint::builtin::UNUSED_VARIABLES,
var_hir_id,
vec![span],
- |lint| {
- lint.build(&format!("unused variable: `{}`", name))
- .help("did you mean to capture by reference instead?")
- .emit();
- },
+ format!("unused variable: `{}`", name),
+ |lint| lint.help("did you mean to capture by reference instead?"),
);
}
}
@@ -1601,20 +1591,17 @@ impl<'tcx> Liveness<'_, 'tcx> {
.into_iter()
.map(|(_, _, ident_span)| ident_span)
.collect::<Vec<_>>(),
- |lint| {
- lint.build(&format!("variable `{}` is assigned to, but never used", name))
- .note(&format!("consider using `_{}` instead", name))
- .emit();
- },
+ format!("variable `{}` is assigned to, but never used", name),
+ |lint| lint.note(&format!("consider using `_{}` instead", name)),
)
} else if can_remove {
self.ir.tcx.struct_span_lint_hir(
lint::builtin::UNUSED_VARIABLES,
first_hir_id,
hir_ids_and_spans.iter().map(|(_, pat_span, _)| *pat_span).collect::<Vec<_>>(),
+ format!("unused variable: `{}`", name),
|lint| {
- let mut err = lint.build(&format!("unused variable: `{}`", name));
- err.multipart_suggestion(
+ lint.multipart_suggestion(
"try removing the field",
hir_ids_and_spans
.iter()
@@ -1629,8 +1616,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
})
.collect(),
Applicability::MachineApplicable,
- );
- err.emit();
+ )
},
);
} else {
@@ -1661,14 +1647,13 @@ impl<'tcx> Liveness<'_, 'tcx> {
.iter()
.map(|(_, pat_span, _)| *pat_span)
.collect::<Vec<_>>(),
+ format!("unused variable: `{}`", name),
|lint| {
- let mut err = lint.build(&format!("unused variable: `{}`", name));
- err.multipart_suggestion(
+ lint.multipart_suggestion(
"try ignoring the field",
shorthands,
Applicability::MachineApplicable,
- );
- err.emit();
+ )
},
);
} else {
@@ -1684,17 +1669,16 @@ impl<'tcx> Liveness<'_, 'tcx> {
.iter()
.map(|(_, _, ident_span)| *ident_span)
.collect::<Vec<_>>(),
+ format!("unused variable: `{}`", name),
|lint| {
- let mut err = lint.build(&format!("unused variable: `{}`", name));
- if self.has_added_lit_match_name_span(&name, opt_body, &mut err) {
- err.span_label(pat.span, "unused variable");
+ if self.has_added_lit_match_name_span(&name, opt_body, lint) {
+ lint.span_label(pat.span, "unused variable");
}
- err.multipart_suggestion(
+ lint.multipart_suggestion(
"if this is intentional, prefix it with an underscore",
non_shorthands,
Applicability::MachineApplicable,
- );
- err.emit();
+ )
},
);
}
@@ -1758,11 +1742,8 @@ impl<'tcx> Liveness<'_, 'tcx> {
lint::builtin::UNUSED_ASSIGNMENTS,
hir_id,
spans,
- |lint| {
- lint.build(&message(&name))
- .help("maybe it is overwritten before being read?")
- .emit();
- },
+ message(&name),
+ |lint| lint.help("maybe it is overwritten before being read?"),
)
}
}
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index cdda0e388..077194ec6 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -1,6 +1,5 @@
use Context::*;
-use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, Visitor};
@@ -13,6 +12,11 @@ use rustc_session::Session;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::Span;
+use crate::errors::{
+ BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop,
+ UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
+};
+
#[derive(Clone, Copy, Debug, PartialEq)]
enum Context {
Normal,
@@ -90,7 +94,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
Ok(loop_id) => Some(loop_id),
Err(hir::LoopIdError::OutsideLoopScope) => None,
Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
- self.emit_unlabled_cf_in_while_condition(e.span, "break");
+ self.sess.emit_err(UnlabeledCfInWhileCondition {
+ span: e.span,
+ cf_type: "break",
+ });
None
}
Err(hir::LoopIdError::UnresolvedLabel) => None,
@@ -116,69 +123,22 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
match loop_kind {
None | Some(hir::LoopSource::Loop) => (),
Some(kind) => {
- let mut err = struct_span_err!(
- self.sess,
- e.span,
- E0571,
- "`break` with value from a `{}` loop",
- kind.name()
- );
- err.span_label(
- e.span,
- "can only break with a value inside `loop` or breakable block",
+ let suggestion = format!(
+ "break{}",
+ break_label
+ .label
+ .map_or_else(String::new, |l| format!(" {}", l.ident))
);
- if let Some(head) = head {
- err.span_label(
- head,
- &format!(
- "you can't `break` with a value in a `{}` loop",
- kind.name()
- ),
- );
- }
- err.span_suggestion(
- e.span,
- &format!(
- "use `break` on its own without a value inside this `{}` loop",
- kind.name(),
- ),
- format!(
- "break{}",
- break_label
- .label
- .map_or_else(String::new, |l| format!(" {}", l.ident))
- ),
- Applicability::MaybeIncorrect,
- );
- if let (Some(label), None) = (loop_label, break_label.label) {
- match break_expr.kind {
- hir::ExprKind::Path(hir::QPath::Resolved(
- None,
- hir::Path {
- segments: [segment],
- res: hir::def::Res::Err,
- ..
- },
- )) if label.ident.to_string()
- == format!("'{}", segment.ident) =>
- {
- // This error is redundant, we will have already emitted a
- // suggestion to use the label when `segment` wasn't found
- // (hence the `Res::Err` check).
- err.delay_as_bug();
- }
- _ => {
- err.span_suggestion(
- break_expr.span,
- "alternatively, you might have meant to use the \
- available loop label",
- label.ident,
- Applicability::MaybeIncorrect,
- );
- }
- }
- }
- err.emit();
+ self.sess.emit_err(BreakNonLoop {
+ span: e.span,
+ head,
+ kind: kind.name(),
+ suggestion,
+ loop_label,
+ break_label: break_label.label,
+ break_expr_kind: &break_expr.kind,
+ break_expr_span: break_expr.span,
+ });
}
}
}
@@ -191,19 +151,17 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
match destination.target_id {
Ok(loop_id) => {
if let Node::Block(block) = self.hir_map.find(loop_id).unwrap() {
- struct_span_err!(
- self.sess,
- e.span,
- E0696,
- "`continue` pointing to a labeled block"
- )
- .span_label(e.span, "labeled blocks cannot be `continue`'d")
- .span_label(block.span, "labeled block the `continue` points to")
- .emit();
+ self.sess.emit_err(ContinueLabeledBlock {
+ span: e.span,
+ block_span: block.span,
+ });
}
}
Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
- self.emit_unlabled_cf_in_while_condition(e.span, "continue");
+ self.sess.emit_err(UnlabeledCfInWhileCondition {
+ span: e.span,
+ cf_type: "continue",
+ });
}
Err(_) => {}
}
@@ -226,21 +184,16 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
}
fn require_break_cx(&self, name: &str, span: Span) {
- let err_inside_of = |article, ty, closure_span| {
- struct_span_err!(self.sess, span, E0267, "`{}` inside of {} {}", name, article, ty)
- .span_label(span, format!("cannot `{}` inside of {} {}", name, article, ty))
- .span_label(closure_span, &format!("enclosing {}", ty))
- .emit();
- };
-
match self.cx {
LabeledBlock | Loop(_) => {}
- Closure(closure_span) => err_inside_of("a", "closure", closure_span),
- AsyncClosure(closure_span) => err_inside_of("an", "`async` block", closure_span),
+ Closure(closure_span) => {
+ self.sess.emit_err(BreakInsideClosure { span, closure_span, name });
+ }
+ AsyncClosure(closure_span) => {
+ self.sess.emit_err(BreakInsideAsyncBlock { span, closure_span, name });
+ }
Normal | AnonConst => {
- struct_span_err!(self.sess, span, E0268, "`{}` outside of a loop", name)
- .span_label(span, format!("cannot `{}` outside of a loop", name))
- .emit();
+ self.sess.emit_err(OutsideLoop { span, name });
}
}
}
@@ -251,37 +204,13 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
label: &Destination,
cf_type: &str,
) -> bool {
- if !span.is_desugaring(DesugaringKind::QuestionMark) && self.cx == LabeledBlock {
- if label.label.is_none() {
- struct_span_err!(
- self.sess,
- span,
- E0695,
- "unlabeled `{}` inside of a labeled block",
- cf_type
- )
- .span_label(
- span,
- format!(
- "`{}` statements that would diverge to or through \
- a labeled block need to bear a label",
- cf_type
- ),
- )
- .emit();
- return true;
- }
+ if !span.is_desugaring(DesugaringKind::QuestionMark)
+ && self.cx == LabeledBlock
+ && label.label.is_none()
+ {
+ self.sess.emit_err(UnlabeledInLabeledBlock { span, cf_type });
+ return true;
}
false
}
- fn emit_unlabled_cf_in_while_condition(&mut self, span: Span, cf_type: &str) {
- struct_span_err!(
- self.sess,
- span,
- E0590,
- "`break` or `continue` with no label in the condition of a `while` loop"
- )
- .span_label(span, format!("unlabeled `{}` in the condition of a `while` loop", cf_type))
- .emit();
- }
}
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 607973446..acc54e7e1 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -1,7 +1,6 @@
//! Checks validity of naked functions.
use rustc_ast::InlineAsmOptions;
-use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
@@ -14,6 +13,12 @@ use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
+use crate::errors::{
+ CannotInlineNakedFunction, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions,
+ NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed,
+ UndefinedNakedFunctionAbi,
+};
+
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { check_mod_naked_functions, ..*providers };
}
@@ -56,7 +61,7 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline);
for attr in attrs {
- tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit();
+ tcx.sess.emit_err(CannotInlineNakedFunction { span: attr.span });
}
}
@@ -65,9 +70,12 @@ fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) {
if abi == Abi::Rust {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let span = tcx.def_span(def_id);
- tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, span, |lint| {
- lint.build("Rust ABI is unsupported in naked functions").emit();
- });
+ tcx.emit_spanned_lint(
+ UNDEFINED_NAKED_FUNCTION_ABI,
+ hir_id,
+ span,
+ UndefinedNakedFunctionAbi,
+ );
}
}
@@ -78,12 +86,7 @@ fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) {
hir::PatKind::Wild
| hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, _, None) => {}
_ => {
- tcx.sess
- .struct_span_err(
- param.pat.span,
- "patterns not allowed in naked function parameters",
- )
- .emit();
+ tcx.sess.emit_err(NoPatterns { span: param.pat.span });
}
}
}
@@ -113,14 +116,7 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
)) = expr.kind
{
if self.params.contains(var_hir_id) {
- self.tcx
- .sess
- .struct_span_err(
- expr.span,
- "referencing function parameters is not allowed in naked functions",
- )
- .help("follow the calling convention in asm block to use parameters")
- .emit();
+ self.tcx.sess.emit_err(ParamsNotAllowed { span: expr.span });
return;
}
}
@@ -135,26 +131,21 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<
if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] {
// Ok.
} else {
- let mut diag = struct_span_err!(
- tcx.sess,
- tcx.def_span(def_id),
- E0787,
- "naked functions must contain a single asm block"
- );
-
let mut must_show_error = false;
let mut has_asm = false;
let mut has_err = false;
+ let mut multiple_asms = vec![];
+ let mut non_asms = vec![];
for &(kind, span) in &this.items {
match kind {
ItemKind::Asm if has_asm => {
must_show_error = true;
- diag.span_label(span, "multiple asm blocks are unsupported in naked functions");
+ multiple_asms.push(span);
}
ItemKind::Asm => has_asm = true,
ItemKind::NonAsm => {
must_show_error = true;
- diag.span_label(span, "non-asm is unsupported in naked functions");
+ non_asms.push(span);
}
ItemKind::Err => has_err = true,
}
@@ -164,9 +155,11 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<
// errors, then don't show an additional error. This allows for appending/prepending
// `compile_error!("...")` statements and reduces error noise.
if must_show_error || !has_err {
- diag.emit();
- } else {
- diag.cancel();
+ tcx.sess.emit_err(NakedFunctionsAsmBlock {
+ span: tcx.def_span(def_id),
+ multiple_asms,
+ non_asms,
+ });
}
}
}
@@ -247,13 +240,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
})
.collect();
if !unsupported_operands.is_empty() {
- struct_span_err!(
- self.tcx.sess,
- unsupported_operands,
- E0787,
- "only `const` and `sym` operands are supported in naked functions",
- )
- .emit();
+ self.tcx.sess.emit_err(NakedFunctionsOperands { unsupported_operands });
}
let unsupported_options: Vec<&'static str> = [
@@ -269,14 +256,10 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
.collect();
if !unsupported_options.is_empty() {
- struct_span_err!(
- self.tcx.sess,
+ self.tcx.sess.emit_err(NakedFunctionsAsmOptions {
span,
- E0787,
- "asm options unsupported in naked functions: {}",
- unsupported_options.join(", ")
- )
- .emit();
+ unsupported_options: unsupported_options.join(", "),
+ });
}
if !asm.options.contains(InlineAsmOptions::NORETURN) {
@@ -286,20 +269,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
.map_or_else(|| asm.template_strs.last().unwrap().2, |op| op.1)
.shrink_to_hi();
- struct_span_err!(
- self.tcx.sess,
- span,
- E0787,
- "asm in naked functions must use `noreturn` option"
- )
- .span_suggestion(
- last_span,
- "consider specifying that the asm block is responsible \
- for returning from the function",
- ", options(noreturn)",
- Applicability::MachineApplicable,
- )
- .emit();
+ self.tcx.sess.emit_err(NakedFunctionsMustUseNoreturn { span, last_span });
}
}
}
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index f7e3fac6b..50070869a 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -12,7 +12,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::Node;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
-use rustc_middle::middle::privacy;
+use rustc_middle::middle::privacy::{self, Level};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
use rustc_session::config::CrateType;
@@ -29,7 +29,7 @@ fn item_might_be_inlined(tcx: TyCtxt<'_>, item: &hir::Item<'_>, attrs: &CodegenF
match item.kind {
hir::ItemKind::Fn(ref sig, ..) if sig.header.is_const() => true,
hir::ItemKind::Impl { .. } | hir::ItemKind::Fn(..) => {
- let generics = tcx.generics_of(item.def_id);
+ let generics = tcx.generics_of(item.owner_id);
generics.requires_monomorphization(tcx)
}
_ => false,
@@ -42,7 +42,7 @@ fn method_might_be_inlined(
impl_src: LocalDefId,
) -> bool {
let codegen_fn_attrs = tcx.codegen_fn_attrs(impl_item.hir_id().owner.to_def_id());
- let generics = tcx.generics_of(impl_item.def_id);
+ let generics = tcx.generics_of(impl_item.owner_id);
if codegen_fn_attrs.requests_inline() || generics.requires_monomorphization(tcx) {
return true;
}
@@ -116,6 +116,17 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
intravisit::walk_expr(self, expr)
}
+
+ fn visit_inline_asm(&mut self, asm: &'tcx hir::InlineAsm<'tcx>, id: hir::HirId) {
+ for (op, _) in asm.operands {
+ if let hir::InlineAsmOperand::SymStatic { def_id, .. } = op {
+ if let Some(def_id) = def_id.as_local() {
+ self.reachable_symbols.insert(def_id);
+ }
+ }
+ }
+ intravisit::walk_inline_asm(self, asm, id);
+ }
}
impl<'tcx> ReachableContext<'tcx> {
@@ -153,9 +164,9 @@ impl<'tcx> ReachableContext<'tcx> {
hir::ImplItemKind::Fn(..) => {
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let impl_did = self.tcx.hir().get_parent_item(hir_id);
- method_might_be_inlined(self.tcx, impl_item, impl_did)
+ method_might_be_inlined(self.tcx, impl_item, impl_did.def_id)
}
- hir::ImplItemKind::TyAlias(_) => false,
+ hir::ImplItemKind::Type(_) => false,
},
Some(_) => false,
None => false, // This will happen for default methods.
@@ -216,7 +227,7 @@ impl<'tcx> ReachableContext<'tcx> {
if item_might_be_inlined(
self.tcx,
&item,
- self.tcx.codegen_fn_attrs(item.def_id),
+ self.tcx.codegen_fn_attrs(item.owner_id),
) {
self.visit_nested_body(body);
}
@@ -271,7 +282,7 @@ impl<'tcx> ReachableContext<'tcx> {
self.visit_nested_body(body)
}
}
- hir::ImplItemKind::TyAlias(_) => {}
+ hir::ImplItemKind::Type(_) => {}
},
Node::Expr(&hir::Expr {
kind: hir::ExprKind::Closure(&hir::Closure { body, .. }),
@@ -303,13 +314,13 @@ fn check_item<'tcx>(
tcx: TyCtxt<'tcx>,
id: hir::ItemId,
worklist: &mut Vec<LocalDefId>,
- access_levels: &privacy::AccessLevels,
+ effective_visibilities: &privacy::EffectiveVisibilities,
) {
- if has_custom_linkage(tcx, id.def_id) {
- worklist.push(id.def_id);
+ if has_custom_linkage(tcx, id.owner_id.def_id) {
+ worklist.push(id.owner_id.def_id);
}
- if !matches!(tcx.def_kind(id.def_id), DefKind::Impl) {
+ if !matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
return;
}
@@ -318,8 +329,8 @@ fn check_item<'tcx>(
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
item.kind
{
- if !access_levels.is_reachable(item.def_id) {
- worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id));
+ if !effective_visibilities.is_reachable(item.owner_id.def_id) {
+ worklist.extend(items.iter().map(|ii_ref| ii_ref.id.owner_id.def_id));
let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else {
unreachable!();
@@ -354,7 +365,7 @@ fn has_custom_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
}
fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
- let access_levels = &tcx.privacy_access_levels(());
+ let effective_visibilities = &tcx.effective_visibilities(());
let any_library =
tcx.sess.crate_types().iter().any(|ty| {
@@ -373,7 +384,13 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
// If other crates link to us, they're going to expect to be able to
// use the lang items, so we need to be sure to mark them as
// exported.
- reachable_context.worklist.extend(access_levels.map.keys());
+ reachable_context.worklist = effective_visibilities
+ .iter()
+ .filter_map(|(&id, effective_vis)| {
+ effective_vis.is_public_at_level(Level::ReachableThroughImplTrait).then_some(id)
+ })
+ .collect::<Vec<_>>();
+
for item in tcx.lang_items().items().iter() {
if let Some(def_id) = *item {
if let Some(def_id) = def_id.as_local() {
@@ -393,12 +410,12 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
let crate_items = tcx.hir_crate_items(());
for id in crate_items.items() {
- check_item(tcx, id, &mut reachable_context.worklist, access_levels);
+ check_item(tcx, id, &mut reachable_context.worklist, effective_visibilities);
}
for id in crate_items.impl_items() {
- if has_custom_linkage(tcx, id.def_id) {
- reachable_context.worklist.push(id.def_id);
+ if has_custom_linkage(tcx, id.owner_id.def_id) {
+ reachable_context.worklist.push(id.owner_id.def_id);
}
}
}
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 9ba127609..78afa2f25 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -1,12 +1,18 @@
//! A pass that annotates every item and method with its stability level,
//! propagating default levels lexically from parent to children ast nodes.
+use crate::errors::{
+ self, CannotStabilizeDeprecated, DeprecatedAttribute, DuplicateFeatureErr,
+ FeatureOnlyOnNightly, ImpliedFeatureNotExist, InvalidDeprecationVersion, InvalidStability,
+ MissingConstErr, MissingConstStabAttr, MissingStabilityAttr, TraitImplConstStable,
+ UnknownFeature, UselessStability,
+};
use rustc_attr::{
self as attr, rust_version_symbol, ConstStability, Stability, StabilityLevel, Unstable,
UnstableReason, VERSION_PLACEHOLDER,
};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
-use rustc_errors::{struct_span_err, Applicability};
+use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
@@ -14,12 +20,11 @@ use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
use rustc_middle::hir::nested_filter;
-use rustc_middle::middle::privacy::AccessLevels;
+use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index};
use rustc_middle::ty::{query::Providers, TyCtxt};
use rustc_session::lint;
use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED};
-use rustc_session::Session;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
@@ -122,16 +127,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
if kind == AnnotationKind::Prohibited || kind == AnnotationKind::DeprecationProhibited {
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- self.tcx.struct_span_lint_hir(USELESS_DEPRECATED, hir_id, *span, |lint| {
- lint.build("this `#[deprecated]` annotation has no effect")
- .span_suggestion_short(
- *span,
- "remove the unnecessary deprecation attribute",
- "",
- rustc_errors::Applicability::MachineApplicable,
- )
- .emit();
- });
+ self.tcx.emit_spanned_lint(
+ USELESS_DEPRECATED,
+ hir_id,
+ *span,
+ errors::DeprecatedAnnotationHasNoEffect { span: *span },
+ );
}
// `Deprecation` is just two pointers, no need to intern it
@@ -182,7 +183,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
if !self.in_trait_impl
|| (self.in_trait_impl && !self.tcx.is_const_fn_raw(def_id.to_def_id()))
{
- missing_const_err(&self.tcx.sess, fn_sig.span, const_span);
+ self.tcx
+ .sess
+ .emit_err(MissingConstErr { fn_sig_span: fn_sig.span, const_span });
}
}
}
@@ -200,14 +203,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
if let Some((rustc_attr::Deprecation { is_since_rustc_version: true, .. }, span)) = &depr {
if stab.is_none() {
- struct_span_err!(
- self.tcx.sess,
- *span,
- E0549,
- "deprecated attribute must be paired with \
- either stable or unstable attribute"
- )
- .emit();
+ self.tcx.sess.emit_err(DeprecatedAttribute { span: *span });
}
}
@@ -223,10 +219,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
if kind == AnnotationKind::Prohibited
|| (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
{
- self.tcx.sess.struct_span_err(span,"this stability annotation is useless")
- .span_label(span, "useless stability annotation")
- .span_label(item_sp, "the stability attribute annotates this item")
- .emit();
+ self.tcx.sess.emit_err(UselessStability { span, item_sp });
}
debug!("annotate: found {:?}", stab);
@@ -242,19 +235,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
{
match stab_v.parse::<u64>() {
Err(_) => {
- self.tcx.sess.struct_span_err(span, "invalid stability version found")
- .span_label(span, "invalid stability version")
- .span_label(item_sp, "the stability attribute annotates this item")
- .emit();
+ self.tcx.sess.emit_err(InvalidStability { span, item_sp });
break;
}
Ok(stab_vp) => match dep_v.parse::<u64>() {
Ok(dep_vp) => match dep_vp.cmp(&stab_vp) {
Ordering::Less => {
- self.tcx.sess.struct_span_err(span, "an API can't be stabilized after it is deprecated")
- .span_label(span, "invalid version")
- .span_label(item_sp, "the stability attribute annotates this item")
- .emit();
+ self.tcx
+ .sess
+ .emit_err(CannotStabilizeDeprecated { span, item_sp });
break;
}
Ordering::Equal => continue,
@@ -262,10 +251,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
},
Err(_) => {
if dep_v != "TBD" {
- self.tcx.sess.struct_span_err(span, "invalid deprecation version found")
- .span_label(span, "invalid deprecation version")
- .span_label(item_sp, "the stability attribute annotates this item")
- .emit();
+ self.tcx
+ .sess
+ .emit_err(InvalidDeprecationVersion { span, item_sp });
}
break;
}
@@ -274,7 +262,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
}
}
- if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } = stab {
+ if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } =
+ stab
+ {
self.index.implications.insert(implied_by, feature);
}
@@ -388,7 +378,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
}
self.annotate(
- i.def_id,
+ i.owner_id.def_id,
i.span,
fn_sig,
kind,
@@ -407,7 +397,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
};
self.annotate(
- ti.def_id,
+ ti.owner_id.def_id,
ti.span,
fn_sig,
AnnotationKind::Required,
@@ -430,7 +420,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
};
self.annotate(
- ii.def_id,
+ ii.owner_id.def_id,
ii.span,
fn_sig,
kind,
@@ -488,7 +478,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
self.annotate(
- i.def_id,
+ i.owner_id.def_id,
i.span,
None,
AnnotationKind::Required,
@@ -526,15 +516,18 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
struct MissingStabilityAnnotations<'tcx> {
tcx: TyCtxt<'tcx>,
- access_levels: &'tcx AccessLevels,
+ effective_visibilities: &'tcx EffectiveVisibilities,
}
impl<'tcx> MissingStabilityAnnotations<'tcx> {
fn check_missing_stability(&self, def_id: LocalDefId, span: Span) {
let stab = self.tcx.stability().local_stability(def_id);
- if !self.tcx.sess.opts.test && stab.is_none() && self.access_levels.is_reachable(def_id) {
+ if !self.tcx.sess.opts.test
+ && stab.is_none()
+ && self.effective_visibilities.is_reachable(def_id)
+ {
let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
- self.tcx.sess.span_err(span, &format!("{} has missing stability attribute", descr));
+ self.tcx.sess.emit_err(MissingStabilityAttr { span, descr });
}
}
@@ -550,11 +543,11 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
.lookup_stability(def_id)
.map_or(false, |stability| stability.level.is_stable());
let missing_const_stability_attribute = self.tcx.lookup_const_stability(def_id).is_none();
- let is_reachable = self.access_levels.is_reachable(def_id);
+ let is_reachable = self.effective_visibilities.is_reachable(def_id);
if is_const && is_stable && missing_const_stability_attribute && is_reachable {
let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
- self.tcx.sess.span_err(span, &format!("{descr} has missing const stability attribute"));
+ self.tcx.sess.emit_err(MissingConstStabAttr { span, descr });
}
}
}
@@ -576,25 +569,25 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
| hir::ItemKind::ForeignMod { .. }
) {
- self.check_missing_stability(i.def_id, i.span);
+ self.check_missing_stability(i.owner_id.def_id, i.span);
}
// Ensure stable `const fn` have a const stability attribute.
- self.check_missing_const_stability(i.def_id, i.span);
+ self.check_missing_const_stability(i.owner_id.def_id, i.span);
intravisit::walk_item(self, i)
}
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
- self.check_missing_stability(ti.def_id, ti.span);
+ self.check_missing_stability(ti.owner_id.def_id, ti.span);
intravisit::walk_trait_item(self, ti);
}
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id());
if self.tcx.impl_trait_ref(impl_def_id).is_none() {
- self.check_missing_stability(ii.def_id, ii.span);
- self.check_missing_const_stability(ii.def_id, ii.span);
+ self.check_missing_stability(ii.owner_id.def_id, ii.span);
+ self.check_missing_const_stability(ii.owner_id.def_id, ii.span);
}
intravisit::walk_impl_item(self, ii);
}
@@ -613,7 +606,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
}
fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
- self.check_missing_stability(i.def_id, i.span);
+ self.check_missing_stability(i.owner_id.def_id, i.span);
intravisit::walk_foreign_item(self, i);
}
// Note that we don't need to `check_missing_stability` for default generic parameters,
@@ -719,7 +712,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
return;
}
- let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.def_id) else {
+ let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.owner_id.def_id) else {
return;
};
let def_id = cnum.as_def_id();
@@ -755,10 +748,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
item.hir_id(),
span,
- |lint| {lint
- .build("an `#[unstable]` annotation here has no effect")
- .note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")
- .emit();}
+ "an `#[unstable]` annotation here has no effect",
+ |lint| lint.note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")
);
}
}
@@ -769,16 +760,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
&& *constness == hir::Constness::Const
&& const_stab.map_or(false, |(stab, _)| stab.is_const_stable())
{
- self.tcx
- .sess
- .struct_span_err(item.span, "trait implementations cannot be const stable yet")
- .note("see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information")
- .emit();
+ self.tcx.sess.emit_err(TraitImplConstStable { span: item.span });
}
}
for impl_item_ref in *items {
- let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id);
+ let impl_item = self.tcx.associated_item(impl_item_ref.id.owner_id);
if let Some(def_id) = impl_item.trait_item_def_id {
// Pass `None` to skip deprecation warnings.
@@ -872,7 +859,7 @@ fn is_unstable_reexport<'tcx>(tcx: TyCtxt<'tcx>, id: hir::HirId) -> bool {
}
// If this is a path that isn't a use, we don't need to do anything special
- if !matches!(tcx.hir().item(hir::ItemId { def_id }).kind, ItemKind::Use(..)) {
+ if !matches!(tcx.hir().expect_item(def_id).kind, ItemKind::Use(..)) {
return false;
}
@@ -907,8 +894,25 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
if let TyKind::Never = t.kind {
self.fully_stable = false;
}
+ if let TyKind::BareFn(f) = t.kind {
+ if rustc_target::spec::abi::is_stable(f.abi.name()).is_err() {
+ self.fully_stable = false;
+ }
+ }
intravisit::walk_ty(self, t)
}
+
+ fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
+ for ty in fd.inputs {
+ self.visit_ty(ty)
+ }
+ if let hir::FnRetTy::Return(output_ty) = fd.output {
+ match output_ty.kind {
+ TyKind::Never => {} // `-> !` is stable
+ _ => self.visit_ty(output_ty),
+ }
+ }
+ }
}
/// Given the list of enabled features that were not language features (i.e., that
@@ -918,8 +922,8 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
let is_staged_api =
tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api;
if is_staged_api {
- let access_levels = &tcx.privacy_access_levels(());
- let mut missing = MissingStabilityAnnotations { tcx, access_levels };
+ let effective_visibilities = &tcx.effective_visibilities(());
+ let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities };
missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
tcx.hir().walk_toplevel_module(&mut missing);
tcx.hir().visit_all_item_likes_in_crate(&mut missing);
@@ -934,7 +938,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
}
if !lang_features.insert(feature) {
// Warn if the user enables a lang feature multiple times.
- duplicate_feature_err(tcx.sess, span, feature);
+ tcx.sess.emit_err(DuplicateFeatureErr { span, feature });
}
}
@@ -942,18 +946,14 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
let mut remaining_lib_features = FxIndexMap::default();
for (feature, span) in declared_lib_features {
if !tcx.sess.opts.unstable_features.is_nightly_build() {
- struct_span_err!(
- tcx.sess,
- *span,
- E0554,
- "`#![feature]` may not be used on the {} release channel",
- env!("CFG_RELEASE_CHANNEL")
- )
- .emit();
+ tcx.sess.emit_err(FeatureOnlyOnNightly {
+ span: *span,
+ release_channel: env!("CFG_RELEASE_CHANNEL"),
+ });
}
if remaining_lib_features.contains_key(&feature) {
// Warn if the user enables a lib feature multiple times.
- duplicate_feature_err(tcx.sess, *span, *feature);
+ tcx.sess.emit_err(DuplicateFeatureErr { span: *span, feature: *feature });
}
remaining_lib_features.insert(feature, *span);
}
@@ -1054,23 +1054,18 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
}
for (feature, span) in remaining_lib_features {
- struct_span_err!(tcx.sess, span, E0635, "unknown feature `{}`", feature).emit();
+ tcx.sess.emit_err(UnknownFeature { span, feature: *feature });
}
for (implied_by, feature) in remaining_implications {
let local_defined_features = tcx.lib_features(());
- let span = local_defined_features
+ let span = *local_defined_features
.stable
.get(&feature)
.map(|(_, span)| span)
.or_else(|| local_defined_features.unstable.get(&feature))
.expect("feature that implied another does not exist");
- tcx.sess
- .struct_span_err(
- *span,
- format!("feature `{implied_by}` implying `{feature}` does not exist"),
- )
- .emit();
+ tcx.sess.emit_err(ImpliedFeatureNotExist { span, feature, implied_by });
}
// FIXME(#44232): the `used_features` table no longer exists, so we
@@ -1084,27 +1079,31 @@ fn unnecessary_partially_stable_feature_lint(
implies: Symbol,
since: Symbol,
) {
- tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| {
- lint.build(&format!(
+ tcx.struct_span_lint_hir(
+ 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}`"
- ))
- .span_suggestion(
- span,
- &format!(
+ ),
+ |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,
- )
- .emit();
- });
+ 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,
+ )
+ },
+ );
}
fn unnecessary_stable_feature_lint(
@@ -1116,28 +1115,7 @@ 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, |lint| {
- lint.build(&format!(
- "the feature `{feature}` has been stable since {since} and no longer requires an \
- attribute to enable",
- ))
- .emit();
+ 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
});
}
-
-fn duplicate_feature_err(sess: &Session, span: Span, feature: Symbol) {
- struct_span_err!(sess, span, E0636, "the feature `{}` has already been declared", feature)
- .emit();
-}
-
-fn missing_const_err(session: &Session, fn_sig_span: Span, const_span: Span) {
- const ERROR_MSG: &'static str = "attributes `#[rustc_const_unstable]` \
- and `#[rustc_const_stable]` require \
- the function or method to be `const`";
-
- session
- .struct_span_err(fn_sig_span, ERROR_MSG)
- .span_help(fn_sig_span, "make the function or method const")
- .span_label(const_span, "attribute specified here")
- .emit();
-}
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index c48b4ecf8..959ee600c 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -1,13 +1,17 @@
//! Validity checking for weak lang items
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
use rustc_hir::lang_items::{self, LangItem};
use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS;
use rustc_middle::middle::lang_items::required;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::CrateType;
+use crate::errors::{
+ AllocFuncRequired, MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler,
+ UnknownExternLangItem,
+};
+
/// Checks the crate for usage of weak lang items, returning a vector of all the
/// language items required by this crate, but not defined yet.
pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItems) {
@@ -30,15 +34,8 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem
items.missing.push(item);
}
} else {
- let span = tcx.def_span(id.def_id);
- struct_span_err!(
- tcx.sess,
- span,
- E0264,
- "unknown external lang item: `{}`",
- lang_item
- )
- .emit();
+ let span = tcx.def_span(id.owner_id);
+ tcx.sess.emit_err(UnknownExternLangItem { span, lang_item });
}
}
}
@@ -71,20 +68,14 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) {
for (name, &item) in WEAK_ITEMS_REFS.iter() {
if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() {
if item == LangItem::PanicImpl {
- tcx.sess.err("`#[panic_handler]` function required, but not found");
+ tcx.sess.emit_err(MissingPanicHandler);
} else if item == LangItem::Oom {
if !tcx.features().default_alloc_error_handler {
- tcx.sess.err("`#[alloc_error_handler]` function required, but not found");
- tcx.sess.note_without_error("use `#![feature(default_alloc_error_handler)]` for a default error handler");
+ tcx.sess.emit_err(AllocFuncRequired);
+ tcx.sess.emit_note(MissingAllocErrorHandler);
}
} else {
- tcx
- .sess
- .diagnostic()
- .struct_err(&format!("language item required, but not found: `{}`", name))
- .note(&format!("this can occur when a binary crate with `#![no_std]` is compiled for a target where `{}` is defined in the standard library", name))
- .help(&format!("you may be able to compile for a target that doesn't need `{}`, specify a target with `--target` or in `.cargo/config`", name))
- .emit();
+ tcx.sess.emit_err(MissingLangItem { name: *name });
}
}
}
diff --git a/compiler/rustc_plugin_impl/Cargo.toml b/compiler/rustc_plugin_impl/Cargo.toml
index c409b6c3e..fa27bfc61 100644
--- a/compiler/rustc_plugin_impl/Cargo.toml
+++ b/compiler/rustc_plugin_impl/Cargo.toml
@@ -5,7 +5,6 @@ build = false
edition = "2021"
[lib]
-doctest = false
[dependencies]
libloading = "0.7.1"
diff --git a/compiler/rustc_plugin_impl/src/errors.rs b/compiler/rustc_plugin_impl/src/errors.rs
index 2bdb6e4fe..e6a7fc86b 100644
--- a/compiler/rustc_plugin_impl/src/errors.rs
+++ b/compiler/rustc_plugin_impl/src/errors.rs
@@ -1,18 +1,18 @@
//! Errors emitted by plugin_impl
-use rustc_macros::SessionDiagnostic;
+use rustc_macros::Diagnostic;
use rustc_span::Span;
-#[derive(SessionDiagnostic)]
-#[diag(plugin_impl::load_plugin_error)]
+#[derive(Diagnostic)]
+#[diag(plugin_impl_load_plugin_error)]
pub struct LoadPluginError {
#[primary_span]
pub span: Span,
pub msg: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(plugin_impl::malformed_plugin_attribute, code = "E0498")]
+#[derive(Diagnostic)]
+#[diag(plugin_impl_malformed_plugin_attribute, code = "E0498")]
pub struct MalformedPluginAttribute {
#[primary_span]
#[label]
diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml
index 5785921fb..832fdc9f0 100644
--- a/compiler/rustc_privacy/Cargo.toml
+++ b/compiler/rustc_privacy/Cargo.toml
@@ -14,5 +14,5 @@ rustc_middle = { path = "../rustc_middle" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
-rustc_typeck = { path = "../rustc_typeck" }
+rustc_hir_analysis = { path = "../rustc_hir_analysis" }
tracing = "0.1"
diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs
index 63f83f896..a6c95f1a8 100644
--- a/compiler/rustc_privacy/src/errors.rs
+++ b/compiler/rustc_privacy/src/errors.rs
@@ -1,9 +1,9 @@
use rustc_errors::DiagnosticArgFromDisplay;
-use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_span::{Span, Symbol};
-#[derive(SessionDiagnostic)]
-#[diag(privacy::field_is_private, code = "E0451")]
+#[derive(Diagnostic)]
+#[diag(privacy_field_is_private, code = "E0451")]
pub struct FieldIsPrivate {
#[primary_span]
pub span: Span,
@@ -14,23 +14,23 @@ pub struct FieldIsPrivate {
pub label: FieldIsPrivateLabel,
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub enum FieldIsPrivateLabel {
- #[label(privacy::field_is_private_is_update_syntax_label)]
+ #[label(privacy_field_is_private_is_update_syntax_label)]
IsUpdateSyntax {
#[primary_span]
span: Span,
field_name: Symbol,
},
- #[label(privacy::field_is_private_label)]
+ #[label(privacy_field_is_private_label)]
Other {
#[primary_span]
span: Span,
},
}
-#[derive(SessionDiagnostic)]
-#[diag(privacy::item_is_private)]
+#[derive(Diagnostic)]
+#[diag(privacy_item_is_private)]
pub struct ItemIsPrivate<'a> {
#[primary_span]
#[label]
@@ -39,8 +39,8 @@ pub struct ItemIsPrivate<'a> {
pub descr: DiagnosticArgFromDisplay<'a>,
}
-#[derive(SessionDiagnostic)]
-#[diag(privacy::unnamed_item_is_private)]
+#[derive(Diagnostic)]
+#[diag(privacy_unnamed_item_is_private)]
pub struct UnnamedItemIsPrivate {
#[primary_span]
pub span: Span,
@@ -48,8 +48,8 @@ pub struct UnnamedItemIsPrivate {
}
// Duplicate of `InPublicInterface` but with a different error code, shares the same slug.
-#[derive(SessionDiagnostic)]
-#[diag(privacy::in_public_interface, code = "E0445")]
+#[derive(Diagnostic)]
+#[diag(privacy_in_public_interface, code = "E0445")]
pub struct InPublicInterfaceTraits<'a> {
#[primary_span]
#[label]
@@ -57,13 +57,13 @@ pub struct InPublicInterfaceTraits<'a> {
pub vis_descr: &'static str,
pub kind: &'a str,
pub descr: DiagnosticArgFromDisplay<'a>,
- #[label(privacy::visibility_label)]
+ #[label(visibility_label)]
pub vis_span: Span,
}
// Duplicate of `InPublicInterfaceTraits` but with a different error code, shares the same slug.
-#[derive(SessionDiagnostic)]
-#[diag(privacy::in_public_interface, code = "E0446")]
+#[derive(Diagnostic)]
+#[diag(privacy_in_public_interface, code = "E0446")]
pub struct InPublicInterface<'a> {
#[primary_span]
#[label]
@@ -71,20 +71,20 @@ pub struct InPublicInterface<'a> {
pub vis_descr: &'static str,
pub kind: &'a str,
pub descr: DiagnosticArgFromDisplay<'a>,
- #[label(privacy::visibility_label)]
+ #[label(visibility_label)]
pub vis_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(privacy::report_access_level)]
-pub struct ReportAccessLevel {
+#[derive(Diagnostic)]
+#[diag(privacy_report_effective_visibility)]
+pub struct ReportEffectiveVisibility {
#[primary_span]
pub span: Span,
pub descr: String,
}
#[derive(LintDiagnostic)]
-#[diag(privacy::from_private_dep_in_public_interface)]
+#[diag(privacy_from_private_dep_in_public_interface)]
pub struct FromPrivateDependencyInPublicInterface<'a> {
pub kind: &'a str,
pub descr: DiagnosticArgFromDisplay<'a>,
@@ -92,7 +92,7 @@ pub struct FromPrivateDependencyInPublicInterface<'a> {
}
#[derive(LintDiagnostic)]
-#[diag(privacy::private_in_public_lint)]
+#[diag(privacy_private_in_public_lint)]
pub struct PrivateInPublicLint<'a> {
pub vis_descr: &'static str,
pub kind: &'a str,
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 48ab31ab9..865d6306b 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1,7 +1,6 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(associated_type_defaults)]
#![feature(control_flow_enum)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(rustc_private)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
@@ -24,7 +23,7 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind};
use rustc_middle::bug;
use rustc_middle::hir::nested_filter;
-use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
+use rustc_middle::middle::privacy::{EffectiveVisibilities, Level};
use rustc_middle::span_bug;
use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst, Node as ACNode};
use rustc_middle::ty::query::Providers;
@@ -42,7 +41,7 @@ use std::{cmp, fmt, mem};
use errors::{
FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface,
- InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, ReportAccessLevel,
+ InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, ReportEffectiveVisibility,
UnnamedItemIsPrivate,
};
@@ -123,8 +122,20 @@ where
&mut self,
projection: ty::ProjectionTy<'tcx>,
) -> ControlFlow<V::BreakTy> {
- let (trait_ref, assoc_substs) =
- projection.trait_ref_and_own_substs(self.def_id_visitor.tcx());
+ let tcx = self.def_id_visitor.tcx();
+ let (trait_ref, assoc_substs) = if tcx.def_kind(projection.item_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(projection.item_def_id);
+ let trait_generics = tcx.generics_of(def_id);
+ (
+ ty::TraitRef { def_id, substs: 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
@@ -148,34 +159,12 @@ where
ty.visit_with(self)
}
ty::PredicateKind::RegionOutlives(..) => ControlFlow::CONTINUE,
- ty::PredicateKind::ConstEvaluatable(uv)
- if self.def_id_visitor.tcx().features().generic_const_exprs =>
- {
- let tcx = self.def_id_visitor.tcx();
- if let Ok(Some(ct)) = AbstractConst::new(tcx, uv) {
- self.visit_abstract_const_expr(tcx, ct)?;
- }
- ControlFlow::CONTINUE
- }
+ ty::PredicateKind::ConstEvaluatable(ct) => ct.visit_with(self),
ty::PredicateKind::WellFormed(arg) => arg.visit_with(self),
_ => bug!("unexpected predicate: {:?}", predicate),
}
}
- fn visit_abstract_const_expr(
- &mut self,
- tcx: TyCtxt<'tcx>,
- ct: AbstractConst<'tcx>,
- ) -> ControlFlow<V::BreakTy> {
- walk_abstract_const(tcx, ct, |node| match node.root(tcx) {
- ACNode::Leaf(leaf) => self.visit_const(leaf),
- ACNode::Cast(_, _, ty) => self.visit_ty(ty),
- ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
- ControlFlow::CONTINUE
- }
- })
- }
-
fn visit_predicates(
&mut self,
predicates: ty::GenericPredicates<'tcx>,
@@ -298,9 +287,16 @@ where
self.visit_ty(c.ty())?;
let tcx = self.def_id_visitor.tcx();
if let Ok(Some(ct)) = AbstractConst::from_const(tcx, c) {
- self.visit_abstract_const_expr(tcx, ct)?;
+ walk_abstract_const(tcx, ct, |node| match node.root(tcx) {
+ ACNode::Leaf(leaf) => self.visit_const(leaf),
+ ACNode::Cast(_, _, ty) => self.visit_ty(ty),
+ ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
+ ControlFlow::CONTINUE
+ }
+ })
+ } else {
+ ControlFlow::CONTINUE
}
- ControlFlow::CONTINUE
}
}
@@ -314,7 +310,7 @@ fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visib
struct FindMin<'a, 'tcx, VL: VisibilityLike> {
tcx: TyCtxt<'tcx>,
- access_levels: &'a AccessLevels,
+ effective_visibilities: &'a EffectiveVisibilities,
min: VL,
}
@@ -348,8 +344,12 @@ trait VisibilityLike: Sized {
// Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to
// associated types for which we can't determine visibility precisely.
- fn of_impl(def_id: LocalDefId, tcx: TyCtxt<'_>, access_levels: &AccessLevels) -> Self {
- let mut find = FindMin { tcx, access_levels, min: Self::MAX };
+ fn of_impl(
+ def_id: LocalDefId,
+ tcx: TyCtxt<'_>,
+ effective_visibilities: &EffectiveVisibilities,
+ ) -> Self {
+ let mut find = FindMin { tcx, effective_visibilities, min: Self::MAX };
find.visit(tcx.type_of(def_id));
if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
find.visit_trait(trait_ref);
@@ -363,8 +363,8 @@ impl VisibilityLike for ty::Visibility {
min(find.tcx.local_visibility(def_id), find.min, find.tcx)
}
}
-impl VisibilityLike for Option<AccessLevel> {
- const MAX: Self = Some(AccessLevel::Public);
+impl VisibilityLike for Option<Level> {
+ const MAX: Self = Some(Level::Direct);
// 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> { ... }`
@@ -376,7 +376,7 @@ impl VisibilityLike for Option<AccessLevel> {
// (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.access_levels.map.get(&def_id).copied(), find.min)
+ cmp::min(find.effective_visibilities.public_at_level(def_id), find.min)
}
}
@@ -387,8 +387,8 @@ impl VisibilityLike for Option<AccessLevel> {
struct EmbargoVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
- /// Accessibility levels for reachable nodes.
- access_levels: AccessLevels,
+ /// Effective visibilities for reachable nodes.
+ effective_visibilities: EffectiveVisibilities,
/// A set of pairs corresponding to modules, where the first module is
/// reachable via a macro that's defined in the second module. This cannot
/// be represented as reachable because it can't handle the following case:
@@ -402,38 +402,38 @@ struct EmbargoVisitor<'tcx> {
/// n::p::f()
/// }
macro_reachable: FxHashSet<(LocalDefId, LocalDefId)>,
- /// Previous accessibility level; `None` means unreachable.
- prev_level: Option<AccessLevel>,
+ /// Previous visibility level; `None` means unreachable.
+ prev_level: Option<Level>,
/// Has something changed in the level map?
changed: bool,
}
struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
- access_level: Option<AccessLevel>,
+ level: Option<Level>,
item_def_id: LocalDefId,
ev: &'a mut EmbargoVisitor<'tcx>,
}
impl<'tcx> EmbargoVisitor<'tcx> {
- fn get(&self, def_id: LocalDefId) -> Option<AccessLevel> {
- self.access_levels.map.get(&def_id).copied()
+ fn get(&self, def_id: LocalDefId) -> Option<Level> {
+ self.effective_visibilities.public_at_level(def_id)
}
- fn update_with_hir_id(
- &mut self,
- hir_id: hir::HirId,
- level: Option<AccessLevel>,
- ) -> Option<AccessLevel> {
+ fn update_with_hir_id(&mut self, hir_id: hir::HirId, level: Option<Level>) -> Option<Level> {
let def_id = self.tcx.hir().local_def_id(hir_id);
self.update(def_id, level)
}
/// Updates node level and returns the updated level.
- fn update(&mut self, def_id: LocalDefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
+ fn update(&mut self, def_id: LocalDefId, level: Option<Level>) -> Option<Level> {
let old_level = self.get(def_id);
- // Accessibility levels can only grow.
+ // Visibility levels can only grow.
if level > old_level {
- self.access_levels.map.insert(def_id, level.unwrap());
+ self.effective_visibilities.set_public_at_level(
+ def_id,
+ || ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)),
+ level.unwrap(),
+ );
self.changed = true;
level
} else {
@@ -444,10 +444,10 @@ impl<'tcx> EmbargoVisitor<'tcx> {
fn reach(
&mut self,
def_id: LocalDefId,
- access_level: Option<AccessLevel>,
+ level: Option<Level>,
) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
ReachEverythingInTheInterfaceVisitor {
- access_level: cmp::min(access_level, Some(AccessLevel::Reachable)),
+ level: cmp::min(level, Some(Level::Reachable)),
item_def_id: def_id,
ev: self,
}
@@ -505,9 +505,9 @@ impl<'tcx> EmbargoVisitor<'tcx> {
fn update_macro_reachable_mod(&mut self, module_def_id: LocalDefId, defining_mod: LocalDefId) {
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.def_id);
- let vis = self.tcx.local_visibility(item_id.def_id);
- self.update_macro_reachable_def(item_id.def_id, def_kind, vis, defining_mod);
+ 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);
}
if let Some(exports) = self.tcx.module_reexports(module_def_id) {
for export in exports {
@@ -530,7 +530,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
vis: ty::Visibility,
module: LocalDefId,
) {
- let level = Some(AccessLevel::Reachable);
+ let level = Some(Level::Reachable);
if vis.is_public() {
self.update(def_id, level);
}
@@ -627,11 +627,14 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
let item_level = match item.kind {
hir::ItemKind::Impl { .. } => {
- let impl_level =
- Option::<AccessLevel>::of_impl(item.def_id, self.tcx, &self.access_levels);
- self.update(item.def_id, impl_level)
+ 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.def_id),
+ _ => self.get(item.owner_id.def_id),
};
// Update levels of nested things.
@@ -650,15 +653,15 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
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.def_id).is_public()
+ || self.tcx.visibility(impl_item_ref.id.owner_id).is_public()
{
- self.update(impl_item_ref.id.def_id, item_level);
+ 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.def_id, item_level);
+ self.update(trait_item_ref.id.owner_id.def_id, item_level);
}
}
hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
@@ -674,12 +677,12 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
}
}
hir::ItemKind::Macro(ref macro_def, _) => {
- self.update_reachability_from_macro(item.def_id, 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.def_id).is_public() {
- self.update(foreign_item.id.def_id, item_level);
+ if self.tcx.visibility(foreign_item.id.owner_id).is_public() {
+ self.update(foreign_item.id.owner_id.def_id, item_level);
}
}
}
@@ -702,7 +705,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
hir::ItemKind::Macro(..) | hir::ItemKind::ExternCrate(..) => {}
// All nested items are checked by `visit_item`.
hir::ItemKind::Mod(..) => {}
- // Handled in the access level of in rustc_resolve
+ // Handled in `rustc_resolve`.
hir::ItemKind::Use(..) => {}
// The interface is empty.
hir::ItemKind::GlobalAsm(..) => {}
@@ -715,9 +718,8 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
// 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(AccessLevel::ReachableFromImplTrait));
- self.reach(item.def_id, exist_level).generics().predicates().ty();
+ let exist_level = cmp::max(item_level, Some(Level::ReachableThroughImplTrait));
+ self.reach(item.owner_id.def_id, exist_level).generics().predicates().ty();
}
}
// Visit everything.
@@ -726,20 +728,20 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
| hir::ItemKind::Fn(..)
| hir::ItemKind::TyAlias(..) => {
if item_level.is_some() {
- self.reach(item.def_id, item_level).generics().predicates().ty();
+ self.reach(item.owner_id.def_id, item_level).generics().predicates().ty();
}
}
hir::ItemKind::Trait(.., trait_item_refs) => {
if item_level.is_some() {
- self.reach(item.def_id, item_level).generics().predicates();
+ self.reach(item.owner_id.def_id, item_level).generics().predicates();
for trait_item_ref in trait_item_refs {
let tcx = self.tcx;
- let mut reach = self.reach(trait_item_ref.id.def_id, item_level);
+ let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_level);
reach.generics().predicates();
if trait_item_ref.kind == AssocItemKind::Type
- && !tcx.impl_defaultness(trait_item_ref.id.def_id).has_value()
+ && !tcx.impl_defaultness(trait_item_ref.id.owner_id).has_value()
{
// No type to visit.
} else {
@@ -750,18 +752,22 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
}
hir::ItemKind::TraitAlias(..) => {
if item_level.is_some() {
- self.reach(item.def_id, item_level).generics().predicates();
+ self.reach(item.owner_id.def_id, item_level).generics().predicates();
}
}
// Visit everything except for private impl items.
hir::ItemKind::Impl(ref impl_) => {
if item_level.is_some() {
- self.reach(item.def_id, item_level).generics().predicates().ty().trait_ref();
+ self.reach(item.owner_id.def_id, item_level)
+ .generics()
+ .predicates()
+ .ty()
+ .trait_ref();
for impl_item_ref in impl_.items {
- let impl_item_level = self.get(impl_item_ref.id.def_id);
+ 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.def_id, impl_item_level)
+ self.reach(impl_item_ref.id.owner_id.def_id, impl_item_level)
.generics()
.predicates()
.ty();
@@ -773,7 +779,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
// Visit everything, but enum variants have their own levels.
hir::ItemKind::Enum(ref def, _) => {
if item_level.is_some() {
- self.reach(item.def_id, item_level).generics().predicates();
+ self.reach(item.owner_id.def_id, item_level).generics().predicates();
}
for variant in def.variants {
let variant_level = self.get(self.tcx.hir().local_def_id(variant.id));
@@ -784,13 +790,13 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
}
// Corner case: if the variant is reachable, but its
// enum is not, make the enum reachable as well.
- self.reach(item.def_id, variant_level).ty();
+ self.reach(item.owner_id.def_id, variant_level).ty();
}
if let Some(hir_id) = variant.data.ctor_hir_id() {
let ctor_def_id = self.tcx.hir().local_def_id(hir_id);
let ctor_level = self.get(ctor_def_id);
if ctor_level.is_some() {
- self.reach(item.def_id, ctor_level).ty();
+ self.reach(item.owner_id.def_id, ctor_level).ty();
}
}
}
@@ -798,9 +804,9 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
// 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.def_id);
+ let foreign_item_level = self.get(foreign_item.id.owner_id.def_id);
if foreign_item_level.is_some() {
- self.reach(foreign_item.id.def_id, foreign_item_level)
+ self.reach(foreign_item.id.owner_id.def_id, foreign_item_level)
.generics()
.predicates()
.ty();
@@ -810,7 +816,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
// 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.def_id, item_level).generics().predicates();
+ self.reach(item.owner_id.def_id, item_level).generics().predicates();
for field in struct_def.fields() {
let def_id = self.tcx.hir().local_def_id(field.hir_id);
let field_level = self.get(def_id);
@@ -823,7 +829,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
let ctor_def_id = self.tcx.hir().local_def_id(hir_id);
let ctor_level = self.get(ctor_def_id);
if ctor_level.is_some() {
- self.reach(item.def_id, ctor_level).ty();
+ self.reach(item.owner_id.def_id, ctor_level).ty();
}
}
}
@@ -894,10 +900,10 @@ 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(AccessLevel::ReachableFromImplTrait)) =
- (self.tcx().visibility(def_id.to_def_id()), self.access_level)
+ if let (ty::Visibility::Public, _) | (_, Some(Level::ReachableThroughImplTrait)) =
+ (self.tcx().visibility(def_id.to_def_id()), self.level)
{
- self.ev.update(def_id, self.access_level);
+ self.ev.update(def_id, self.level);
}
}
ControlFlow::CONTINUE
@@ -905,42 +911,64 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx>
}
////////////////////////////////////////////////////////////////////////////////
-/// Visitor, used for AccessLevels table checking
+/// Visitor, used for EffectiveVisibilities table checking
////////////////////////////////////////////////////////////////////////////////
pub struct TestReachabilityVisitor<'tcx, 'a> {
tcx: TyCtxt<'tcx>,
- access_levels: &'a AccessLevels,
+ effective_visibilities: &'a EffectiveVisibilities,
}
impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> {
- fn access_level_diagnostic(&mut self, def_id: LocalDefId) {
- if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_access_level) {
- let access_level = format!("{:?}", self.access_levels.map.get(&def_id));
+ fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) {
+ if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_effective_visibility) {
+ let mut error_msg = String::new();
let span = self.tcx.def_span(def_id.to_def_id());
- self.tcx.sess.emit_err(ReportAccessLevel { span, descr: access_level });
+ if let Some(effective_vis) = self.effective_visibilities.effective_vis(def_id) {
+ for level in Level::all_levels() {
+ let vis_str = match effective_vis.at_level(level) {
+ ty::Visibility::Restricted(restricted_id) => {
+ if restricted_id.is_top_level_module() {
+ "pub(crate)".to_string()
+ } else if *restricted_id == self.tcx.parent_module_from_def_id(def_id) {
+ "pub(self)".to_string()
+ } else {
+ format!("pub({})", self.tcx.item_name(restricted_id.to_def_id()))
+ }
+ }
+ ty::Visibility::Public => "pub".to_string(),
+ };
+ if level != Level::Direct {
+ error_msg.push_str(", ");
+ }
+ error_msg.push_str(&format!("{:?}: {}", level, vis_str));
+ }
+ } else {
+ error_msg.push_str("not in the table");
+ }
+ self.tcx.sess.emit_err(ReportEffectiveVisibility { span, descr: error_msg });
}
}
}
impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> {
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
- self.access_level_diagnostic(item.def_id);
+ self.effective_visibility_diagnostic(item.owner_id.def_id);
match item.kind {
hir::ItemKind::Enum(ref def, _) => {
for variant in def.variants.iter() {
let variant_id = self.tcx.hir().local_def_id(variant.id);
- self.access_level_diagnostic(variant_id);
+ self.effective_visibility_diagnostic(variant_id);
for field in variant.data.fields() {
let def_id = self.tcx.hir().local_def_id(field.hir_id);
- self.access_level_diagnostic(def_id);
+ self.effective_visibility_diagnostic(def_id);
}
}
}
hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
for field in def.fields() {
let def_id = self.tcx.hir().local_def_id(field.hir_id);
- self.access_level_diagnostic(def_id);
+ self.effective_visibility_diagnostic(def_id);
}
}
_ => {}
@@ -948,13 +976,13 @@ impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> {
}
fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) {
- self.access_level_diagnostic(item.def_id);
+ self.effective_visibility_diagnostic(item.owner_id.def_id);
}
fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) {
- self.access_level_diagnostic(item.def_id);
+ self.effective_visibility_diagnostic(item.owner_id.def_id);
}
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
- self.access_level_diagnostic(item.def_id);
+ self.effective_visibility_diagnostic(item.owner_id.def_id);
}
}
@@ -1025,7 +1053,7 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) {
// Don't visit nested modules, since we run a separate visitor walk
- // for each module in `privacy_access_levels`
+ // for each module in `effective_visibilities`
}
fn visit_nested_body(&mut self, body: hir::BodyId) {
@@ -1037,7 +1065,7 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
}
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
- let orig_current_item = mem::replace(&mut self.current_item, item.def_id);
+ let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id);
intravisit::walk_item(self, item);
self.current_item = orig_current_item;
}
@@ -1150,7 +1178,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) {
// Don't visit nested modules, since we run a separate visitor walk
- // for each module in `privacy_access_levels`
+ // for each module in `effective_visibilities`
}
fn visit_nested_body(&mut self, body: hir::BodyId) {
@@ -1180,7 +1208,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
// Types in signatures.
// FIXME: This is very ineffective. Ideally each HIR type should be converted
// into a semantic type only once and the result should be cached somehow.
- if self.visit(rustc_typeck::hir_ty_to_ty(self.tcx, hir_ty)).is_break() {
+ if self.visit(rustc_hir_analysis::hir_ty_to_ty(self.tcx, hir_ty)).is_break() {
return;
}
}
@@ -1209,7 +1237,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
if self.maybe_typeck_results.is_none() {
// Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
// The traits' privacy in bodies is already checked as a part of trait object types.
- let bounds = rustc_typeck::hir_trait_to_predicates(
+ let bounds = rustc_hir_analysis::hir_trait_to_predicates(
self.tcx,
trait_ref,
// NOTE: This isn't really right, but the actual type doesn't matter here. It's
@@ -1340,7 +1368,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
// Check types in item interfaces.
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
- let orig_current_item = mem::replace(&mut self.current_item, item.def_id);
+ let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id);
let old_maybe_typeck_results = self.maybe_typeck_results.take();
intravisit::walk_item(self, item);
self.maybe_typeck_results = old_maybe_typeck_results;
@@ -1375,7 +1403,7 @@ impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
struct ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
- access_levels: &'a AccessLevels,
+ effective_visibilities: &'a EffectiveVisibilities,
in_variant: bool,
// Set of errors produced by this obsolete visitor.
old_error_set: HirIdSet,
@@ -1395,7 +1423,9 @@ struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
fn path_is_private_type(&self, path: &hir::Path<'_>) -> bool {
let did = match path.res {
- Res::PrimTy(..) | Res::SelfTy { .. } | Res::Err => return false,
+ Res::PrimTy(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Err => {
+ return false;
+ }
res => res.def_id(),
};
@@ -1416,7 +1446,7 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
fn trait_is_public(&self, trait_id: LocalDefId) -> bool {
// FIXME: this would preferably be using `exported_items`, but all
// traits are exported currently (see `EmbargoVisitor.exported_trait`).
- self.access_levels.is_public(trait_id)
+ self.effective_visibilities.is_directly_public(trait_id)
}
fn check_generic_bound(&mut self, bound: &hir::GenericBound<'_>) {
@@ -1428,7 +1458,7 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
}
fn item_is_public(&self, def_id: LocalDefId) -> bool {
- self.access_levels.is_reachable(def_id) || self.tcx.visibility(def_id).is_public()
+ self.effective_visibilities.is_reachable(def_id) || self.tcx.visibility(def_id).is_public()
}
}
@@ -1482,7 +1512,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
hir::ItemKind::ForeignMod { .. } => {}
hir::ItemKind::Trait(.., bounds, _) => {
- if !self.trait_is_public(item.def_id) {
+ if !self.trait_is_public(item.owner_id.def_id) {
return;
}
@@ -1542,10 +1572,10 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
|| impl_.items.iter().any(|impl_item_ref| {
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
match impl_item.kind {
- hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) => {
- self.access_levels.is_reachable(impl_item_ref.id.def_id)
- }
- hir::ImplItemKind::TyAlias(_) => false,
+ hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) => self
+ .effective_visibilities
+ .is_reachable(impl_item_ref.id.owner_id.def_id),
+ hir::ImplItemKind::Type(_) => false,
}
});
@@ -1563,11 +1593,11 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
match impl_item.kind {
hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..)
- if self.item_is_public(impl_item.def_id) =>
+ if self.item_is_public(impl_item.owner_id.def_id) =>
{
intravisit::walk_impl_item(self, impl_item)
}
- hir::ImplItemKind::TyAlias(..) => {
+ hir::ImplItemKind::Type(..) => {
intravisit::walk_impl_item(self, impl_item)
}
_ => {}
@@ -1593,7 +1623,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
// Those in 3. are warned with this call.
for impl_item_ref in impl_.items {
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
- if let hir::ImplItemKind::TyAlias(ty) = impl_item.kind {
+ if let hir::ImplItemKind::Type(ty) = impl_item.kind {
self.visit_ty(ty);
}
}
@@ -1604,8 +1634,10 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
// methods will be visible as `Public::foo`.
let mut found_pub_static = false;
for impl_item_ref in impl_.items {
- if self.access_levels.is_reachable(impl_item_ref.id.def_id)
- || self.tcx.visibility(impl_item_ref.id.def_id).is_public()
+ if self
+ .effective_visibilities
+ .is_reachable(impl_item_ref.id.owner_id.def_id)
+ || self.tcx.visibility(impl_item_ref.id.owner_id).is_public()
{
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
match impl_item_ref.kind {
@@ -1633,7 +1665,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
hir::ItemKind::TyAlias(..) => return,
// Not at all public, so we don't care.
- _ if !self.item_is_public(item.def_id) => {
+ _ if !self.item_is_public(item.owner_id.def_id) => {
return;
}
@@ -1664,7 +1696,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
}
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
- if self.access_levels.is_reachable(item.def_id) {
+ if self.effective_visibilities.is_reachable(item.owner_id.def_id) {
intravisit::walk_foreign_item(self, item)
}
}
@@ -1679,7 +1711,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
}
fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
- if self.access_levels.is_reachable(self.tcx.hir().local_def_id(v.id)) {
+ if self.effective_visibilities.is_reachable(self.tcx.hir().local_def_id(v.id)) {
self.in_variant = true;
intravisit::walk_variant(self, v);
self.in_variant = false;
@@ -1901,43 +1933,44 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
pub fn check_item(&mut self, id: ItemId) {
let tcx = self.tcx;
- let item_visibility = tcx.local_visibility(id.def_id);
- let def_kind = tcx.def_kind(id.def_id);
+ let def_id = id.owner_id.def_id;
+ let item_visibility = tcx.local_visibility(def_id);
+ let def_kind = tcx.def_kind(def_id);
match def_kind {
DefKind::Const | DefKind::Static(_) | DefKind::Fn | DefKind::TyAlias => {
- self.check(id.def_id, item_visibility).generics().predicates().ty();
+ self.check(def_id, item_visibility).generics().predicates().ty();
}
DefKind::OpaqueTy => {
// `ty()` for opaque types is the underlying type,
// it's not a part of interface, so we skip it.
- self.check(id.def_id, item_visibility).generics().bounds();
+ self.check(def_id, item_visibility).generics().bounds();
}
DefKind::Trait => {
let item = tcx.hir().item(id);
if let hir::ItemKind::Trait(.., trait_item_refs) = item.kind {
- self.check(item.def_id, item_visibility).generics().predicates();
+ self.check(item.owner_id.def_id, item_visibility).generics().predicates();
for trait_item_ref in trait_item_refs {
self.check_assoc_item(
- trait_item_ref.id.def_id,
+ trait_item_ref.id.owner_id.def_id,
trait_item_ref.kind,
item_visibility,
);
if let AssocItemKind::Type = trait_item_ref.kind {
- self.check(trait_item_ref.id.def_id, item_visibility).bounds();
+ self.check(trait_item_ref.id.owner_id.def_id, item_visibility).bounds();
}
}
}
}
DefKind::TraitAlias => {
- self.check(id.def_id, item_visibility).generics().predicates();
+ self.check(def_id, item_visibility).generics().predicates();
}
DefKind::Enum => {
let item = tcx.hir().item(id);
if let hir::ItemKind::Enum(ref def, _) = item.kind {
- self.check(item.def_id, item_visibility).generics().predicates();
+ self.check(item.owner_id.def_id, item_visibility).generics().predicates();
for variant in def.variants {
for field in variant.data.fields() {
@@ -1952,8 +1985,11 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
let item = tcx.hir().item(id);
if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
for foreign_item in items {
- let vis = tcx.local_visibility(foreign_item.id.def_id);
- self.check(foreign_item.id.def_id, vis).generics().predicates().ty();
+ let vis = tcx.local_visibility(foreign_item.id.owner_id.def_id);
+ self.check(foreign_item.id.owner_id.def_id, vis)
+ .generics()
+ .predicates()
+ .ty();
}
}
}
@@ -1963,7 +1999,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
if let hir::ItemKind::Struct(ref struct_def, _)
| hir::ItemKind::Union(ref struct_def, _) = item.kind
{
- self.check(item.def_id, item_visibility).generics().predicates();
+ self.check(item.owner_id.def_id, item_visibility).generics().predicates();
for field in struct_def.fields() {
let def_id = tcx.hir().local_def_id(field.hir_id);
@@ -1979,20 +2015,25 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
DefKind::Impl => {
let item = tcx.hir().item(id);
if let hir::ItemKind::Impl(ref impl_) = item.kind {
- let impl_vis = ty::Visibility::of_impl(item.def_id, tcx, &Default::default());
+ let impl_vis =
+ ty::Visibility::of_impl(item.owner_id.def_id, tcx, &Default::default());
// check that private components do not appear in the generics or predicates of inherent impls
// this check is intentionally NOT performed for impls of traits, per #90586
if impl_.of_trait.is_none() {
- self.check(item.def_id, impl_vis).generics().predicates();
+ self.check(item.owner_id.def_id, impl_vis).generics().predicates();
}
for impl_item_ref in impl_.items {
let impl_item_vis = if impl_.of_trait.is_none() {
- min(tcx.local_visibility(impl_item_ref.id.def_id), impl_vis, tcx)
+ min(
+ tcx.local_visibility(impl_item_ref.id.owner_id.def_id),
+ impl_vis,
+ tcx,
+ )
} else {
impl_vis
};
self.check_assoc_item(
- impl_item_ref.id.def_id,
+ impl_item_ref.id.owner_id.def_id,
impl_item_ref.kind,
impl_item_vis,
);
@@ -2007,7 +2048,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
pub fn provide(providers: &mut Providers) {
*providers = Providers {
visibility,
- privacy_access_levels,
+ effective_visibilities,
check_private_in_public,
check_mod_privacy,
..*providers
@@ -2040,7 +2081,7 @@ fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility {
// Visibilities of trait impl items are inherited from their traits
// and are not filled in resolve.
Node::ImplItem(impl_item) => {
- match tcx.hir().get_by_def_id(tcx.hir().get_parent_item(hir_id)) {
+ match tcx.hir().get_by_def_id(tcx.hir().get_parent_item(hir_id).def_id) {
Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { of_trait: Some(tr), .. }),
..
@@ -2079,14 +2120,14 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
intravisit::walk_mod(&mut visitor, module, hir_id);
}
-fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels {
+fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
// Build up a set of all exported items in the AST. This is a set of all
// items which are reachable from external crates based on visibility.
let mut visitor = EmbargoVisitor {
tcx,
- access_levels: tcx.resolutions(()).access_levels.clone(),
+ effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(),
macro_reachable: Default::default(),
- prev_level: Some(AccessLevel::Public),
+ prev_level: Some(Level::Direct),
changed: false,
};
@@ -2099,18 +2140,19 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels {
}
}
- let mut check_visitor = TestReachabilityVisitor { tcx, access_levels: &visitor.access_levels };
+ let mut check_visitor =
+ TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities };
tcx.hir().visit_all_item_likes_in_crate(&mut check_visitor);
- tcx.arena.alloc(visitor.access_levels)
+ tcx.arena.alloc(visitor.effective_visibilities)
}
fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
- let access_levels = tcx.privacy_access_levels(());
+ let effective_visibilities = tcx.effective_visibilities(());
let mut visitor = ObsoleteVisiblePrivateTypesVisitor {
tcx,
- access_levels,
+ effective_visibilities,
in_variant: false,
old_error_set: Default::default(),
};
diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs
index 49175e97f..8be2e2be8 100644
--- a/compiler/rustc_query_impl/src/keys.rs
+++ b/compiler/rustc_query_impl/src/keys.rs
@@ -1,6 +1,7 @@
//! Defines the set of legal keys that can be used in queries.
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::hir_id::{HirId, OwnerId};
use rustc_middle::infer::canonical::Canonical;
use rustc_middle::mir;
use rustc_middle::traits;
@@ -26,6 +27,10 @@ pub trait Key {
fn key_as_def_id(&self) -> Option<DefId> {
None
}
+
+ fn ty_adt_id(&self) -> Option<DefId> {
+ None
+ }
}
impl Key for () {
@@ -104,6 +109,19 @@ impl Key for CrateNum {
}
}
+impl Key for OwnerId {
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
+ }
+ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+ self.to_def_id().default_span(tcx)
+ }
+ fn key_as_def_id(&self) -> Option<DefId> {
+ Some(self.to_def_id())
+ }
+}
+
impl Key for LocalDefId {
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
@@ -275,7 +293,7 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) {
}
}
-impl<'tcx> Key for (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>) {
+impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) {
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
(self.0).def.did.krate == LOCAL_CRATE
@@ -393,6 +411,12 @@ impl<'tcx> Key for Ty<'tcx> {
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
+ fn ty_adt_id(&self) -> Option<DefId> {
+ match self.kind() {
+ ty::Adt(adt, _) => Some(adt.did()),
+ _ => None,
+ }
+ }
}
impl<'tcx> Key for TyAndLayout<'tcx> {
@@ -543,3 +567,19 @@ impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) {
DUMMY_SP
}
}
+
+impl Key for HirId {
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
+ }
+
+ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+ tcx.hir().span(*self)
+ }
+
+ #[inline(always)]
+ fn key_as_def_id(&self) -> Option<DefId> {
+ None
+ }
+}
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index c87d26b39..11d4c97e7 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -1,6 +1,8 @@
//! Support for serializing the dep-graph and reloading it.
#![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(min_specialization)]
#![feature(never_type)]
#![feature(once_cell)]
@@ -20,8 +22,7 @@ use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::{self, DepKindStruct};
use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values};
use rustc_middle::ty::query::{ExternProviders, Providers, QueryEngine};
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::def_id::{LocalDefId, LOCAL_CRATE};
+use rustc_middle::ty::TyCtxt;
use rustc_span::Span;
#[macro_use]
@@ -43,14 +44,6 @@ pub use on_disk_cache::OnDiskCache;
mod profiling_support;
pub use self::profiling_support::alloc_self_profile_query_strings;
-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()))
- }
-}
-
rustc_query_append! { define_queries! }
impl<'tcx> Queries<'tcx> {
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index 0e93f3ce1..9000f81d9 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -1,8 +1,9 @@
use crate::QueryCtxt;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::memmap::Mmap;
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};
@@ -118,12 +119,11 @@ pub type EncodedDepNodeIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
struct SourceFileIndex(u32);
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Encodable, Decodable)]
-pub struct AbsoluteBytePos(u32);
+pub struct AbsoluteBytePos(u64);
impl AbsoluteBytePos {
fn new(pos: usize) -> AbsoluteBytePos {
- debug_assert!(pos <= u32::MAX as usize);
- AbsoluteBytePos(pos as u32)
+ AbsoluteBytePos(pos.try_into().expect("Incremental cache file size overflowed u64."))
}
fn to_usize(self) -> usize {
@@ -792,7 +792,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId {
}
}
-impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashSet<LocalDefId> {
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx UnordSet<LocalDefId> {
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
@@ -848,6 +848,7 @@ impl_ref_decoder! {<'tcx>
rustc_span::def_id::DefId,
rustc_span::def_id::LocalDefId,
(rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo),
+ ty::DeducedParamAttrs,
}
//- ENCODING -------------------------------------------------------------------
@@ -1067,7 +1068,7 @@ pub fn encode_query_results<'a, 'tcx, CTX, Q>(
let _timer = tcx
.dep_context()
.profiler()
- .extra_verbose_generic_activity("encode_query_results_for", std::any::type_name::<Q>());
+ .verbose_generic_activity_with_arg("encode_query_results_for", std::any::type_name::<Q>());
assert!(Q::query_state(tcx).all_inactive());
let cache = Q::query_cache(tcx);
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index 6f39bbfc0..1d17f4221 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -3,7 +3,8 @@
//! manage the caches, and so forth.
use crate::keys::Key;
-use crate::on_disk_cache::CacheDecoder;
+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};
@@ -19,8 +20,10 @@ use rustc_query_system::query::{
force_query, QueryConfig, QueryContext, QueryDescription, QueryJobId, QueryMap,
QuerySideEffects, QueryStackFrame,
};
-use rustc_query_system::Value;
+use rustc_query_system::{LayoutOfDepth, QueryOverflow, Value};
use rustc_serialize::Decodable;
+use rustc_session::Limit;
+use rustc_span::def_id::LOCAL_CRATE;
use std::any::Any;
use std::num::NonZeroU64;
use thin_vec::ThinVec;
@@ -109,7 +112,7 @@ impl QueryContext for QueryCtxt<'_> {
// when accessing the `ImplicitCtxt`.
tls::with_related_context(**self, move |current_icx| {
if depth_limit && !self.recursion_limit().value_within_limit(current_icx.query_depth) {
- self.depth_limit_error();
+ self.depth_limit_error(token);
}
// Update the `ImplicitCtxt` to point to our new query job.
@@ -127,6 +130,29 @@ impl QueryContext for QueryCtxt<'_> {
})
})
}
+
+ fn depth_limit_error(&self, job: QueryJobId) {
+ let mut span = None;
+ let mut layout_of_depth = None;
+ if let Some(map) = self.try_collect_active_jobs() {
+ if let Some((info, depth)) = job.try_find_layout_root(map) {
+ span = Some(info.job.span);
+ layout_of_depth = Some(LayoutOfDepth { desc: info.query.description, depth });
+ }
+ }
+
+ let suggested_limit = match self.recursion_limit() {
+ Limit(0) => Limit(2),
+ limit => limit * 2,
+ };
+
+ self.sess.emit_fatal(QueryOverflow {
+ span,
+ layout_of_depth,
+ suggested_limit,
+ crate_name: self.crate_name(LOCAL_CRATE),
+ });
+ }
}
impl<'tcx> QueryCtxt<'tcx> {
@@ -148,34 +174,14 @@ impl<'tcx> QueryCtxt<'tcx> {
pub(super) fn encode_query_results(
self,
- encoder: &mut on_disk_cache::CacheEncoder<'_, 'tcx>,
- query_result_index: &mut on_disk_cache::EncodedDepNodeIndex,
+ encoder: &mut CacheEncoder<'_, 'tcx>,
+ query_result_index: &mut EncodedDepNodeIndex,
) {
- macro_rules! expand_if_cached {
- ([] $encode:expr) => {};
- ([(cache) $($rest:tt)*] $encode:expr) => {
- $encode
- };
- ([$other:tt $($modifiers:tt)*] $encode:expr) => {
- expand_if_cached!([$($modifiers)*] $encode)
- };
- }
-
- macro_rules! encode_queries {
- (
- $($(#[$attr:meta])*
- [$($modifiers:tt)*] fn $query:ident($($K:tt)*) -> $V:ty,)*) => {
- $(
- expand_if_cached!([$($modifiers)*] on_disk_cache::encode_query_results::<_, super::queries::$query<'_>>(
- self,
- encoder,
- query_result_index
- ));
- )*
+ for query in &self.queries.query_structs {
+ if let Some(encode) = query.encode_query_results {
+ encode(self, encoder, query_result_index);
}
}
-
- rustc_query_append!(encode_queries!);
}
pub fn try_print_query_stack(
@@ -188,6 +194,14 @@ impl<'tcx> QueryCtxt<'tcx> {
}
}
+#[derive(Clone, Copy)]
+pub(crate) struct QueryStruct<'tcx> {
+ pub try_collect_active_jobs: fn(QueryCtxt<'tcx>, &mut QueryMap) -> 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)>,
+}
+
macro_rules! handle_cycle_error {
([]) => {{
rustc_query_system::HandleCycleError::Error
@@ -284,7 +298,7 @@ pub(crate) fn create_query_frame<
K: Copy + Key + for<'a> HashStable<StableHashingContext<'a>>,
>(
tcx: QueryCtxt<'tcx>,
- do_describe: fn(QueryCtxt<'tcx>, K) -> String,
+ do_describe: fn(TyCtxt<'tcx>, K) -> String,
key: K,
kind: DepKind,
name: &'static str,
@@ -293,7 +307,7 @@ pub(crate) fn create_query_frame<
// Showing visible path instead of any path is not that important in production.
let description = 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, key))
+ ty::print::with_forced_impl_filename_line!(do_describe(tcx.tcx, key))
);
let description =
if tcx.sess.verbose() { format!("{} [{}]", description, name) } else { description };
@@ -304,13 +318,12 @@ pub(crate) fn create_query_frame<
} else {
Some(key.default_span(*tcx))
};
+ let def_id = key.key_as_def_id();
let def_kind = if kind == dep_graph::DepKind::opt_def_kind {
// Try to avoid infinite recursion.
None
} else {
- key.key_as_def_id()
- .and_then(|def_id| def_id.as_local())
- .and_then(|def_id| tcx.opt_def_kind(def_id))
+ def_id.and_then(|def_id| def_id.as_local()).and_then(|def_id| tcx.opt_def_kind(def_id))
};
let hash = || {
tcx.with_stable_hashing_context(|mut hcx| {
@@ -320,8 +333,9 @@ pub(crate) fn create_query_frame<
hasher.finish::<u64>()
})
};
+ let ty_adt_id = key.ty_adt_id();
- QueryStackFrame::new(name, description, span, def_kind, hash)
+ QueryStackFrame::new(name, description, span, def_id, def_kind, ty_adt_id, hash)
}
fn try_load_from_on_disk_cache<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode)
@@ -355,6 +369,24 @@ where
Q::Key: DepNodeParams<TyCtxt<'tcx>>,
Q::Value: Value<TyCtxt<'tcx>>,
{
+ // We must avoid ever having to call `force_from_dep_node()` for a
+ // `DepNode::codegen_unit`:
+ // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
+ // would always end up having to evaluate the first caller of the
+ // `codegen_unit` query that *is* reconstructible. This might very well be
+ // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
+ // to re-trigger calling the `codegen_unit` query with the right key. At
+ // that point we would already have re-done all the work we are trying to
+ // avoid doing in the first place.
+ // The solution is simple: Just explicitly call the `codegen_unit` query for
+ // each CGU, right after partitioning. This way `try_mark_green` will always
+ // hit the cache instead of having to go through `force_from_dep_node`.
+ // This assertion makes sure, we actually keep applying the solution above.
+ debug_assert!(
+ dep_node.kind != DepKind::codegen_unit,
+ "calling force_from_dep_node() on DepKind::codegen_unit"
+ );
+
if let Some(key) = Q::Key::recover(tcx, &dep_node) {
#[cfg(debug_assertions)]
let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
@@ -395,6 +427,18 @@ where
}
}
+macro_rules! expand_if_cached {
+ ([], $tokens:expr) => {{
+ None
+ }};
+ ([(cache) $($rest:tt)*], $tokens:expr) => {{
+ Some($tokens)
+ }};
+ ([$other:tt $($modifiers:tt)*], $tokens:expr) => {
+ expand_if_cached!([$($modifiers)*], $tokens)
+ };
+}
+
// 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 {
@@ -422,7 +466,10 @@ macro_rules! define_queries {
}
impl<'tcx> QueryDescription<QueryCtxt<'tcx>> for queries::$name<'tcx> {
- rustc_query_description! { $name }
+ #[inline]
+ fn cache_on_disk(tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool {
+ ::rustc_middle::query::cached::$name(tcx, key)
+ }
type Cache = query_storage::$name<'tcx>;
@@ -528,6 +575,59 @@ macro_rules! define_queries {
})*
}
+ mod query_structs {
+ use rustc_middle::ty::TyCtxt;
+ use $crate::plumbing::{QueryStruct, QueryCtxt};
+ use $crate::profiling_support::QueryKeyStringCache;
+ use rustc_query_system::query::QueryMap;
+
+ pub(super) const fn dummy_query_struct<'tcx>() -> QueryStruct<'tcx> {
+ fn noop_try_collect_active_jobs(_: QueryCtxt<'_>, _: &mut QueryMap) -> 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_caches.$name,
+ string_cache,
+ )
+ },
+ encode_query_results: expand_if_cached!([$($modifiers)*], |tcx, encoder, query_result_index|
+ $crate::on_disk_cache::encode_query_results::<_, super::queries::$name<'_>>(tcx, 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))
}
@@ -542,9 +642,11 @@ impl<'tcx> Queries<'tcx> {
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()
@@ -559,6 +661,7 @@ macro_rules! define_queries_struct {
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>>,
@@ -575,18 +678,9 @@ macro_rules! define_queries_struct {
let tcx = QueryCtxt { tcx, queries: self };
let mut jobs = QueryMap::default();
- $(
- let make_query = |tcx, key| {
- let kind = dep_graph::DepKind::$name;
- let name = stringify!($name);
- $crate::plumbing::create_query_frame(tcx, queries::$name::describe, key, kind, name)
- };
- self.$name.try_collect_active_jobs(
- tcx,
- make_query,
- &mut jobs,
- )?;
- )*
+ for query in &self.query_structs {
+ (query.try_collect_active_jobs)(tcx, &mut jobs);
+ }
Some(jobs)
}
diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs
index 98ec3bc09..2cc311d48 100644
--- a/compiler/rustc_query_impl/src/profiling_support.rs
+++ b/compiler/rustc_query_impl/src/profiling_support.rs
@@ -1,3 +1,4 @@
+use crate::QueryCtxt;
use measureme::{StringComponent, StringId};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::profiling::SelfProfiler;
@@ -8,7 +9,7 @@ use rustc_query_system::query::QueryCache;
use std::fmt::Debug;
use std::io::Write;
-struct QueryKeyStringCache {
+pub(crate) struct QueryKeyStringCache {
def_id_cache: FxHashMap<DefId, StringId>,
}
@@ -226,7 +227,7 @@ where
/// Allocate the self-profiling query strings for a single query cache. This
/// method is called from `alloc_self_profile_query_strings` which knows all
/// the queries via macro magic.
-fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
+pub(crate) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
tcx: TyCtxt<'tcx>,
query_name: &'static str,
query_cache: &C,
@@ -298,27 +299,15 @@ fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
/// If we are recording only summary data, the ids will point to
/// just the query names. If we are recording query keys too, we
/// allocate the corresponding strings here.
-pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) {
+pub fn alloc_self_profile_query_strings<'tcx>(tcx: TyCtxt<'tcx>) {
if !tcx.prof.enabled() {
return;
}
let mut string_cache = QueryKeyStringCache::new();
+ let queries = QueryCtxt::from_tcx(tcx);
- macro_rules! alloc_once {
- (
- $($(#[$attr:meta])*
- [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
- $(
- alloc_self_profile_query_strings_for_query_cache(
- tcx,
- stringify!($name),
- &tcx.query_caches.$name,
- &mut string_cache,
- );
- )+
- }
+ for query in &queries.queries.query_structs {
+ (query.alloc_self_profile_query_strings)(tcx, &mut string_cache);
}
-
- rustc_query_append! { alloc_once! }
}
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index d7599a56c..faddad741 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
parking_lot = "0.11"
diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
index 162c274d8..5c6ce0556 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -47,6 +47,7 @@ use crate::ich::StableHashingContext;
use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hir::definitions::DefPathHash;
use std::fmt;
use std::hash::Hash;
@@ -88,6 +89,17 @@ impl<K: DepKind> DepNode<K> {
dep_node
}
+
+ /// Construct a DepNode from the given DepKind and DefPathHash. This
+ /// method will assert that the given DepKind actually requires a
+ /// single DefId/DefPathHash parameter.
+ pub fn from_def_path_hash<Ctxt>(tcx: Ctxt, def_path_hash: DefPathHash, kind: K) -> Self
+ where
+ Ctxt: super::DepContext<DepKind = K>,
+ {
+ debug_assert!(tcx.fingerprint_style(kind) == FingerprintStyle::DefPathHash);
+ DepNode { kind, hash: def_path_hash.0.into() }
+ }
}
impl<K: DepKind> fmt::Debug for DepNode<K> {
@@ -149,6 +161,67 @@ where
}
}
+/// This struct stores metadata about each DepKind.
+///
+/// Information is retrieved by indexing the `DEP_KINDS` array using the integer value
+/// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual
+/// jump table instead of large matches.
+pub struct DepKindStruct<CTX: DepContext> {
+ /// Anonymous queries cannot be replayed from one compiler invocation to the next.
+ /// When their result is needed, it is recomputed. They are useful for fine-grained
+ /// dependency tracking, and caching within one compiler invocation.
+ pub is_anon: bool,
+
+ /// Eval-always queries do not track their dependencies, and are always recomputed, even if
+ /// their inputs have not changed since the last compiler invocation. The result is still
+ /// cached within one compiler invocation.
+ pub is_eval_always: bool,
+
+ /// Whether the query key can be recovered from the hashed fingerprint.
+ /// See [DepNodeParams] trait for the behaviour of each key type.
+ pub fingerprint_style: FingerprintStyle,
+
+ /// The red/green evaluation system will try to mark a specific DepNode in the
+ /// dependency graph as green by recursively trying to mark the dependencies of
+ /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
+ /// where we don't know if it is red or green and we therefore actually have
+ /// to recompute its value in order to find out. Since the only piece of
+ /// information that we have at that point is the `DepNode` we are trying to
+ /// re-evaluate, we need some way to re-run a query from just that. This is what
+ /// `force_from_dep_node()` implements.
+ ///
+ /// In the general case, a `DepNode` consists of a `DepKind` and an opaque
+ /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
+ /// is usually constructed by computing a stable hash of the query-key that the
+ /// `DepNode` corresponds to. Consequently, it is not in general possible to go
+ /// back from hash to query-key (since hash functions are not reversible). For
+ /// this reason `force_from_dep_node()` is expected to fail from time to time
+ /// because we just cannot find out, from the `DepNode` alone, what the
+ /// corresponding query-key is and therefore cannot re-run the query.
+ ///
+ /// The system deals with this case letting `try_mark_green` fail which forces
+ /// the root query to be re-evaluated.
+ ///
+ /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
+ /// Fortunately, we can use some contextual information that will allow us to
+ /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
+ /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
+ /// valid `DefPathHash`. Since we also always build a huge table that maps every
+ /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
+ /// everything we need to re-run the query.
+ ///
+ /// Take the `mir_promoted` query as an example. Like many other queries, it
+ /// just has a single parameter: the `DefId` of the item it will compute the
+ /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
+ /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
+ /// is actually a `DefPathHash`, and can therefore just look up the corresponding
+ /// `DefId` in `tcx.def_path_hash_to_def_id`.
+ pub force_from_dep_node: Option<fn(tcx: CTX, dep_node: DepNode<CTX::DepKind>) -> bool>,
+
+ /// Invoke a query to put the on-disk cached value in memory.
+ pub try_load_from_on_disk_cache: Option<fn(CTX, DepNode<CTX::DepKind>)>,
+}
+
/// A "work product" corresponds to a `.o` (or other) file that we
/// save in between runs. These IDs do not have a `DefId` but rather
/// some independent path or string that persists between runs without
diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs
index 342d95ca4..da2075fd5 100644
--- a/compiler/rustc_query_system/src/dep_graph/mod.rs
+++ b/compiler/rustc_query_system/src/dep_graph/mod.rs
@@ -4,7 +4,7 @@ mod graph;
mod query;
mod serialized;
-pub use dep_node::{DepNode, DepNodeParams, WorkProductId};
+pub use dep_node::{DepKindStruct, DepNode, DepNodeParams, WorkProductId};
pub use graph::{
hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, TaskDepsRef, WorkProduct,
};
@@ -34,16 +34,43 @@ pub trait DepContext: Copy {
/// Access the compiler session.
fn sess(&self) -> &Session;
- /// Return whether this kind always require evaluation.
- fn is_eval_always(&self, kind: Self::DepKind) -> bool;
+ fn dep_kind_info(&self, dep_node: Self::DepKind) -> &DepKindStruct<Self>;
- fn fingerprint_style(&self, kind: Self::DepKind) -> FingerprintStyle;
+ #[inline(always)]
+ fn fingerprint_style(&self, kind: Self::DepKind) -> FingerprintStyle {
+ let data = self.dep_kind_info(kind);
+ if data.is_anon {
+ return FingerprintStyle::Opaque;
+ }
+ data.fingerprint_style
+ }
+
+ #[inline(always)]
+ /// Return whether this kind always require evaluation.
+ fn is_eval_always(&self, kind: Self::DepKind) -> bool {
+ self.dep_kind_info(kind).is_eval_always
+ }
/// Try to force a dep node to execute and see if it's green.
- fn try_force_from_dep_node(&self, dep_node: DepNode<Self::DepKind>) -> bool;
+ fn try_force_from_dep_node(self, dep_node: DepNode<Self::DepKind>) -> bool {
+ debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
+
+ let cb = self.dep_kind_info(dep_node.kind);
+ if let Some(f) = cb.force_from_dep_node {
+ f(self, dep_node);
+ true
+ } else {
+ false
+ }
+ }
/// Load data from the on-disk cache.
- fn try_load_from_on_disk_cache(&self, dep_node: DepNode<Self::DepKind>);
+ fn try_load_from_on_disk_cache(self, dep_node: DepNode<Self::DepKind>) {
+ let cb = self.dep_kind_info(dep_node.kind);
+ if let Some(f) = cb.try_load_from_on_disk_cache {
+ f(self, dep_node)
+ }
+ }
}
pub trait HasDepContext: Copy {
@@ -67,6 +94,8 @@ impl<T: DepContext> HasDepContext for T {
pub enum FingerprintStyle {
/// The fingerprint is actually a DefPathHash.
DefPathHash,
+ /// The fingerprint is actually a HirId.
+ HirId,
/// Query key was `()` or equivalent, so fingerprint is just zero.
Unit,
/// Some opaque hash.
@@ -77,7 +106,9 @@ impl FingerprintStyle {
#[inline]
pub fn reconstructible(self) -> bool {
match self {
- FingerprintStyle::DefPathHash | FingerprintStyle::Unit => true,
+ FingerprintStyle::DefPathHash | FingerprintStyle::Unit | FingerprintStyle::HirId => {
+ true
+ }
FingerprintStyle::Opaque => false,
}
}
diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs
index 3fb06cbed..7a20eaceb 100644
--- a/compiler/rustc_query_system/src/error.rs
+++ b/compiler/rustc_query_system/src/error.rs
@@ -1,17 +1,15 @@
-use rustc_errors::AddSubdiagnostic;
-use rustc_span::Span;
+use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_session::Limit;
+use rustc_span::{Span, Symbol};
+#[derive(Subdiagnostic)]
+#[note(query_system_cycle_stack_middle)]
pub struct CycleStack {
+ #[primary_span]
pub span: Span,
pub desc: String,
}
-impl AddSubdiagnostic for CycleStack {
- fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
- diag.span_note(self.span, &format!("...which requires {}...", self.desc));
- }
-}
-
#[derive(Copy, Clone)]
pub enum HandleCycleError {
Error,
@@ -19,39 +17,39 @@ pub enum HandleCycleError {
DelayBug,
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub enum StackCount {
- #[note(query_system::cycle_stack_single)]
+ #[note(query_system_cycle_stack_single)]
Single,
- #[note(query_system::cycle_stack_multiple)]
+ #[note(query_system_cycle_stack_multiple)]
Multiple,
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub enum Alias {
- #[note(query_system::cycle_recursive_ty_alias)]
- #[help(query_system::cycle_recursive_ty_alias_help1)]
- #[help(query_system::cycle_recursive_ty_alias_help2)]
+ #[note(query_system_cycle_recursive_ty_alias)]
+ #[help(query_system_cycle_recursive_ty_alias_help1)]
+ #[help(query_system_cycle_recursive_ty_alias_help2)]
Ty,
- #[note(query_system::cycle_recursive_trait_alias)]
+ #[note(query_system_cycle_recursive_trait_alias)]
Trait,
}
-#[derive(SessionSubdiagnostic)]
-#[note(query_system::cycle_usage)]
+#[derive(Subdiagnostic)]
+#[note(query_system_cycle_usage)]
pub struct CycleUsage {
#[primary_span]
pub span: Span,
pub usage: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(query_system::cycle, code = "E0391")]
+#[derive(Diagnostic)]
+#[diag(query_system_cycle, code = "E0391")]
pub struct Cycle {
#[primary_span]
pub span: Span,
pub stack_bottom: String,
- #[subdiagnostic]
+ #[subdiagnostic(eager)]
pub cycle_stack: Vec<CycleStack>,
#[subdiagnostic]
pub stack_count: StackCount,
@@ -61,20 +59,35 @@ pub struct Cycle {
pub cycle_usage: Option<CycleUsage>,
}
-#[derive(SessionDiagnostic)]
-#[diag(query_system::reentrant)]
+#[derive(Diagnostic)]
+#[diag(query_system_reentrant)]
pub struct Reentrant;
-#[derive(SessionDiagnostic)]
-#[diag(query_system::increment_compilation)]
+#[derive(Diagnostic)]
+#[diag(query_system_increment_compilation)]
#[help]
-#[note(query_system::increment_compilation_note1)]
-#[note(query_system::increment_compilation_note2)]
+#[note(query_system_increment_compilation_note1)]
+#[note(query_system_increment_compilation_note2)]
pub struct IncrementCompilation {
pub run_cmd: String,
pub dep_node: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(query_system::query_overflow)]
-pub struct QueryOverflow;
+#[derive(Diagnostic)]
+#[help]
+#[diag(query_system_query_overflow)]
+pub struct QueryOverflow {
+ #[primary_span]
+ pub span: Option<Span>,
+ #[subdiagnostic]
+ pub layout_of_depth: Option<LayoutOfDepth>,
+ pub suggested_limit: Limit,
+ pub crate_name: Symbol,
+}
+
+#[derive(Subdiagnostic)]
+#[note(query_system_layout_of_depth)]
+pub struct LayoutOfDepth {
+ pub desc: String,
+ pub depth: usize,
+}
diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs
index a09b8ca30..148eabb38 100644
--- a/compiler/rustc_query_system/src/ich/hcx.rs
+++ b/compiler/rustc_query_system/src/ich/hcx.rs
@@ -12,7 +12,7 @@ use rustc_session::cstore::CrateStore;
use rustc_session::Session;
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::Symbol;
-use rustc_span::{BytePos, CachingSourceMapView, SourceFile, Span, SpanData};
+use rustc_span::{BytePos, CachingSourceMapView, SourceFile, Span, SpanData, DUMMY_SP};
/// This is the context state available during incr. comp. hashing. It contains
/// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e.,
@@ -41,7 +41,10 @@ pub struct StableHashingContext<'a> {
pub(super) enum BodyResolver<'tcx> {
Forbidden,
Ignore,
- Traverse { owner: LocalDefId, bodies: &'tcx SortedMap<hir::ItemLocalId, &'tcx hir::Body<'tcx>> },
+ Traverse {
+ owner: hir::OwnerId,
+ bodies: &'tcx SortedMap<hir::ItemLocalId, &'tcx hir::Body<'tcx>>,
+ },
}
impl<'a> StableHashingContext<'a> {
@@ -103,7 +106,7 @@ impl<'a> StableHashingContext<'a> {
#[inline]
pub fn with_hir_bodies(
&mut self,
- owner: LocalDefId,
+ owner: hir::OwnerId,
bodies: &SortedMap<hir::ItemLocalId, &hir::Body<'_>>,
f: impl FnOnce(&mut StableHashingContext<'_>),
) {
@@ -182,7 +185,7 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
#[inline]
fn def_span(&self, def_id: LocalDefId) -> Span {
- self.source_span[def_id]
+ *self.source_span.get(def_id).unwrap_or(&DUMMY_SP)
}
#[inline]
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index f92c3831f..f47760e9a 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -1,11 +1,10 @@
#![feature(assert_matches)]
#![feature(core_intrinsics)]
#![feature(hash_raw_entry)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(min_specialization)]
#![feature(extern_types)]
#![allow(rustc::potential_query_instability)]
-// #![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
#[macro_use]
@@ -23,4 +22,6 @@ pub mod query;
mod values;
pub use error::HandleCycleError;
+pub use error::LayoutOfDepth;
+pub use error::QueryOverflow;
pub use values::Value;
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index c4549cc9e..0a1cffa3b 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -49,8 +49,6 @@ impl<CTX: QueryContext, K, V> QueryVTable<CTX, K, V> {
pub trait QueryDescription<CTX: QueryContext>: QueryConfig {
type Cache: QueryCache<Key = Self::Key, Stored = Self::Stored, Value = Self::Value>;
- fn describe(tcx: CTX, key: Self::Key) -> String;
-
// Don't use this method to access query results, instead use the methods on TyCtxt
fn query_state<'a>(tcx: CTX) -> &'a QueryState<Self::Key>
where
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 45b4079fb..ed65393f5 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -3,9 +3,11 @@ use crate::query::plumbing::CycleError;
use crate::query::{QueryContext, QueryStackFrame};
use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, Level};
+use rustc_errors::{
+ Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, Level,
+};
use rustc_hir::def::DefKind;
-use rustc_session::{Session, SessionDiagnostic};
+use rustc_session::Session;
use rustc_span::Span;
use std::hash::Hash;
@@ -59,6 +61,7 @@ impl QueryJobId {
}
}
+#[derive(Clone)]
pub struct QueryJobInfo {
pub query: QueryStackFrame,
pub job: QueryJob,
@@ -116,10 +119,10 @@ impl QueryJob {
}
}
-#[cfg(not(parallel_compiler))]
impl QueryJobId {
#[cold]
#[inline(never)]
+ #[cfg(not(parallel_compiler))]
pub(super) fn find_cycle_in_stack(
&self,
query_map: QueryMap,
@@ -156,6 +159,24 @@ impl QueryJobId {
panic!("did not find a cycle")
}
+
+ #[cold]
+ #[inline(never)]
+ pub fn try_find_layout_root(&self, query_map: QueryMap) -> Option<(QueryJobInfo, usize)> {
+ let mut last_layout = None;
+ let mut current_id = Some(*self);
+ let mut depth = 0;
+
+ while let Some(id) = current_id {
+ let info = query_map.get(&id).unwrap();
+ if info.query.name == "layout_of" {
+ depth += 1;
+ last_layout = Some((info.clone(), depth));
+ }
+ current_id = info.job.parent;
+ }
+ last_layout
+ }
}
#[cfg(parallel_compiler)]
@@ -530,7 +551,7 @@ pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) {
#[cold]
pub(crate) fn report_cycle<'a>(
sess: &'a Session,
- CycleError { usage, cycle: stack }: CycleError,
+ CycleError { usage, cycle: stack }: &CycleError,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
assert!(!stack.is_empty());
@@ -548,10 +569,10 @@ pub(crate) fn report_cycle<'a>(
}
let mut cycle_usage = None;
- if let Some((span, query)) = usage {
+ if let Some((span, ref query)) = *usage {
cycle_usage = Some(crate::error::CycleUsage {
span: query.default_span(span),
- usage: query.description,
+ usage: query.description.to_string(),
});
}
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index 0b07bb64b..118703fc0 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -14,10 +14,11 @@ pub use self::caches::{
mod config;
pub use self::config::{QueryConfig, QueryDescription, QueryVTable};
-use crate::dep_graph::{DepContext, DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
+use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
use rustc_data_structures::sync::Lock;
use rustc_errors::Diagnostic;
use rustc_hir::def::DefKind;
+use rustc_span::def_id::DefId;
use rustc_span::Span;
use thin_vec::ThinVec;
@@ -29,7 +30,9 @@ pub struct QueryStackFrame {
pub name: &'static str,
pub description: String,
span: Option<Span>,
- def_kind: Option<DefKind>,
+ pub def_id: Option<DefId>,
+ pub def_kind: Option<DefKind>,
+ pub ty_adt_id: Option<DefId>,
/// This hash is used to deterministically pick
/// a query to remove cycles in the parallel compiler.
#[cfg(parallel_compiler)]
@@ -42,14 +45,18 @@ impl QueryStackFrame {
name: &'static str,
description: String,
span: Option<Span>,
+ def_id: Option<DefId>,
def_kind: Option<DefKind>,
+ ty_adt_id: Option<DefId>,
_hash: impl FnOnce() -> u64,
) -> Self {
Self {
name,
description,
span,
+ def_id,
def_kind,
+ ty_adt_id,
#[cfg(parallel_compiler)]
hash: _hash(),
}
@@ -123,7 +130,5 @@ pub trait QueryContext: HasDepContext {
compute: impl FnOnce() -> R,
) -> R;
- fn depth_limit_error(&self) {
- self.dep_context().sess().emit_fatal(crate::error::QueryOverflow);
- }
+ fn depth_limit_error(&self, job: QueryJobId);
}
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 8179a674a..15b89daa6 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -119,7 +119,7 @@ where
#[inline(never)]
fn mk_cycle<CTX, V, R>(
tcx: CTX,
- error: CycleError,
+ cycle_error: CycleError,
handler: HandleCycleError,
cache: &dyn crate::query::QueryStorage<Value = V, Stored = R>,
) -> R
@@ -128,13 +128,14 @@ where
V: std::fmt::Debug + Value<CTX::DepContext>,
R: Clone,
{
- let error = report_cycle(tcx.dep_context().sess(), error);
- let value = handle_cycle_error(*tcx.dep_context(), error, handler);
+ let error = report_cycle(tcx.dep_context().sess(), &cycle_error);
+ let value = handle_cycle_error(*tcx.dep_context(), &cycle_error, error, handler);
cache.store_nocache(value)
}
fn handle_cycle_error<CTX, V>(
tcx: CTX,
+ cycle_error: &CycleError,
mut error: DiagnosticBuilder<'_, ErrorGuaranteed>,
handler: HandleCycleError,
) -> V
@@ -146,7 +147,7 @@ where
match handler {
Error => {
error.emit();
- Value::from_cycle_error(tcx)
+ Value::from_cycle_error(tcx, &cycle_error.cycle)
}
Fatal => {
error.emit();
@@ -155,7 +156,7 @@ where
}
DelayBug => {
error.delay_as_bug();
- Value::from_cycle_error(tcx)
+ Value::from_cycle_error(tcx, &cycle_error.cycle)
}
}
}
diff --git a/compiler/rustc_query_system/src/values.rs b/compiler/rustc_query_system/src/values.rs
index aeef66f86..67fbf14e6 100644
--- a/compiler/rustc_query_system/src/values.rs
+++ b/compiler/rustc_query_system/src/values.rs
@@ -1,11 +1,12 @@
use crate::dep_graph::DepContext;
+use crate::query::QueryInfo;
pub trait Value<CTX: DepContext>: Sized {
- fn from_cycle_error(tcx: CTX) -> Self;
+ fn from_cycle_error(tcx: CTX, cycle: &[QueryInfo]) -> Self;
}
impl<CTX: DepContext, T> Value<CTX> for T {
- default fn from_cycle_error(tcx: CTX) -> T {
+ default fn from_cycle_error(tcx: CTX, _: &[QueryInfo]) -> T {
tcx.sess().abort_if_errors();
// Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's
// non-trivial to define it earlier.
diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml
index 5d2b606b4..d66db1d7a 100644
--- a/compiler/rustc_resolve/Cargo.toml
+++ b/compiler/rustc_resolve/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
bitflags = "1.2.1"
diff --git a/compiler/rustc_resolve/src/access_levels.rs b/compiler/rustc_resolve/src/access_levels.rs
deleted file mode 100644
index 0a3add2e0..000000000
--- a/compiler/rustc_resolve/src/access_levels.rs
+++ /dev/null
@@ -1,185 +0,0 @@
-use crate::imports::ImportKind;
-use crate::NameBinding;
-use crate::NameBindingKind;
-use crate::Resolver;
-use rustc_ast::ast;
-use rustc_ast::visit;
-use rustc_ast::visit::Visitor;
-use rustc_ast::Crate;
-use rustc_ast::EnumDef;
-use rustc_ast::NodeId;
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::def_id::CRATE_DEF_ID;
-use rustc_middle::middle::privacy::AccessLevel;
-use rustc_middle::ty::DefIdTree;
-use rustc_span::sym;
-
-pub struct AccessLevelsVisitor<'r, 'a> {
- r: &'r mut Resolver<'a>,
- changed: bool,
-}
-
-impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
- /// Fills the `Resolver::access_levels` table with public & exported items
- /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
- /// need access to a TyCtxt for that.
- pub fn compute_access_levels<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
- let mut visitor = AccessLevelsVisitor { r, changed: false };
-
- visitor.set_access_level_def_id(CRATE_DEF_ID, Some(AccessLevel::Public));
- visitor.set_bindings_access_level(CRATE_DEF_ID);
-
- while visitor.changed {
- visitor.reset();
- visit::walk_crate(&mut visitor, krate);
- }
-
- info!("resolve::access_levels: {:#?}", r.access_levels);
- }
-
- fn reset(&mut self) {
- self.changed = false;
- }
-
- /// Update the access level of the bindings in the given module accordingly. The module access
- /// level has to be Exported or Public.
- /// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level).
- fn set_bindings_access_level(&mut self, module_id: LocalDefId) {
- assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
- let module_level = self.r.access_levels.map.get(&module_id).copied();
- if !module_level.is_some() {
- return;
- }
- // Set the given binding access level to `AccessLevel::Public` and
- // sets the rest of the `use` chain to `AccessLevel::Exported` until
- // we hit the actual exported item.
- let set_import_binding_access_level =
- |this: &mut Self, mut binding: &NameBinding<'a>, mut access_level| {
- while let NameBindingKind::Import { binding: nested_binding, import, .. } =
- binding.kind
- {
- this.set_access_level(import.id, access_level);
- if let ImportKind::Single { additional_ids, .. } = import.kind {
- this.set_access_level(additional_ids.0, access_level);
- this.set_access_level(additional_ids.1, access_level);
- }
-
- access_level = Some(AccessLevel::Exported);
- binding = nested_binding;
- }
- };
-
- let module = self.r.get_module(module_id.to_def_id()).unwrap();
- let resolutions = self.r.resolutions(module);
-
- for (.., name_resolution) in resolutions.borrow().iter() {
- if let Some(binding) = name_resolution.borrow().binding() && binding.vis.is_public() && !binding.is_ambiguity() {
- let access_level = match binding.is_import() {
- true => {
- set_import_binding_access_level(self, binding, module_level);
- Some(AccessLevel::Exported)
- },
- false => module_level,
- };
- if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
- self.set_access_level_def_id(def_id, access_level);
- }
- }
- }
- }
-
- /// Sets the access level of the `LocalDefId` corresponding to the given `NodeId`.
- /// This function will panic if the `NodeId` does not have a `LocalDefId`
- fn set_access_level(
- &mut self,
- node_id: NodeId,
- access_level: Option<AccessLevel>,
- ) -> Option<AccessLevel> {
- self.set_access_level_def_id(self.r.local_def_id(node_id), access_level)
- }
-
- fn set_access_level_def_id(
- &mut self,
- def_id: LocalDefId,
- access_level: Option<AccessLevel>,
- ) -> Option<AccessLevel> {
- let old_level = self.r.access_levels.map.get(&def_id).copied();
- if old_level < access_level {
- self.r.access_levels.map.insert(def_id, access_level.unwrap());
- self.changed = true;
- access_level
- } else {
- old_level
- }
- }
-}
-
-impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
- fn visit_item(&mut self, item: &'ast ast::Item) {
- let def_id = self.r.local_def_id(item.id);
- // Set access level of nested items.
- // If it's a mod, also make the visitor walk all of its items
- match item.kind {
- // Resolved in rustc_privacy when types are available
- ast::ItemKind::Impl(..) => return,
-
- // Should be unreachable at this stage
- ast::ItemKind::MacCall(..) => panic!(
- "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
- ),
-
- // Foreign modules inherit level from parents.
- ast::ItemKind::ForeignMod(..) => {
- let parent_level =
- self.r.access_levels.map.get(&self.r.local_parent(def_id)).copied();
- self.set_access_level(item.id, parent_level);
- }
-
- // Only exported `macro_rules!` items are public, but they always are
- ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => {
- if item.attrs.iter().any(|attr| attr.has_name(sym::macro_export)) {
- self.set_access_level(item.id, Some(AccessLevel::Public));
- }
- }
-
- ast::ItemKind::Mod(..) => {
- self.set_bindings_access_level(def_id);
- visit::walk_item(self, item);
- }
-
- ast::ItemKind::Enum(EnumDef { ref variants }, _) => {
- self.set_bindings_access_level(def_id);
- for variant in variants {
- let variant_def_id = self.r.local_def_id(variant.id);
- let variant_level = self.r.access_levels.map.get(&variant_def_id).copied();
- for field in variant.data.fields() {
- self.set_access_level(field.id, variant_level);
- }
- }
- }
-
- ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
- let inherited_level = self.r.access_levels.map.get(&def_id).copied();
- for field in def.fields() {
- if field.vis.kind.is_pub() {
- self.set_access_level(field.id, inherited_level);
- }
- }
- }
-
- ast::ItemKind::Trait(..) => {
- self.set_bindings_access_level(def_id);
- }
-
- ast::ItemKind::ExternCrate(..)
- | ast::ItemKind::Use(..)
- | ast::ItemKind::Static(..)
- | ast::ItemKind::Const(..)
- | ast::ItemKind::GlobalAsm(..)
- | ast::ItemKind::TyAlias(..)
- | ast::ItemKind::TraitAlias(..)
- | ast::ItemKind::MacroDef(..)
- | ast::ItemKind::Fn(..) => return,
- }
- }
-}
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 81b67b758..a17793ecd 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -326,7 +326,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
}
PathResult::Module(..) => Err(VisResolutionError::ModuleOnly(path.span)),
PathResult::NonModule(partial_res) => {
- expected_found_error(partial_res.base_res())
+ expected_found_error(partial_res.expect_full_res())
}
PathResult::Failed { span, label, suggestion, .. } => {
Err(VisResolutionError::FailedToResolve(span, label, suggestion))
@@ -1010,7 +1010,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
_,
)
| Res::Local(..)
- | Res::SelfTy { .. }
+ | Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. }
| Res::SelfCtor(..)
| Res::Err => bug!("unexpected resolution: {:?}", res),
}
@@ -1424,7 +1425,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
}
(DefKind::AssocFn, ValueNS)
}
- AssocItemKind::TyAlias(..) => (DefKind::AssocTy, TypeNS),
+ AssocItemKind::Type(..) => (DefKind::AssocTy, TypeNS),
AssocItemKind::MacCall(_) => bug!(), // handled above
};
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 8b58b32b6..01c3801f2 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -6,7 +6,7 @@
// `use` items.
//
// Unused trait imports can't be checked until the method resolution. We save
-// candidates here, and do the actual check in librustc_typeck/check_unused.rs.
+// candidates here, and do the actual check in rustc_hir_analysis/check_unused.rs.
//
// Checking for unused imports is split into three steps:
//
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 3f88f44ff..d36e0f61d 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -1,6 +1,5 @@
use crate::{ImplTraitContext, Resolver};
use rustc_ast::visit::{self, FnKind};
-use rustc_ast::walk_list;
use rustc_ast::*;
use rustc_expand::expand::AstFragment;
use rustc_hir::def_id::LocalDefId;
@@ -148,8 +147,13 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
self.with_parent(return_impl_trait_id, |this| {
this.visit_fn_ret_ty(&sig.decl.output)
});
- let closure_def = self.create_def(closure_id, DefPathData::ClosureExpr, span);
- self.with_parent(closure_def, |this| walk_list!(this, visit_block, body));
+ // If this async fn has no body (i.e. it's an async fn signature in a trait)
+ // then the closure_def will never be used, and we should avoid generating a
+ // def-id for it.
+ if let Some(body) = body {
+ let closure_def = self.create_def(closure_id, DefPathData::ClosureExpr, span);
+ self.with_parent(closure_def, |this| this.visit_block(body));
+ }
return;
}
}
@@ -235,7 +239,7 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) {
let def_data = match &i.kind {
AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(i.ident.name),
- AssocItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name),
+ AssocItemKind::Type(..) => DefPathData::TypeNs(i.ident.name),
AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
};
@@ -281,21 +285,6 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
fn visit_ty(&mut self, ty: &'a Ty) {
match ty.kind {
TyKind::MacCall(..) => self.visit_macro_invoc(ty.id),
- TyKind::ImplTrait(node_id, _) => {
- let parent_def = match self.impl_trait_context {
- ImplTraitContext::Universal(item_def) => self.resolver.create_def(
- item_def,
- node_id,
- DefPathData::ImplTrait,
- self.expansion.to_expn_id(),
- ty.span,
- ),
- ImplTraitContext::Existential => {
- self.create_def(node_id, DefPathData::ImplTrait, ty.span)
- }
- };
- self.with_parent(parent_def, |this| visit::walk_ty(this, ty))
- }
_ => visit::walk_ty(self, ty),
}
}
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index ab71fa0bc..5d868ebec 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -24,7 +24,7 @@ use rustc_span::hygiene::MacroKind;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, Span};
+use rustc_span::{BytePos, Span, SyntaxContext};
use crate::imports::{Import, ImportKind, ImportResolver};
use crate::late::{PatternSource, Rib};
@@ -47,6 +47,7 @@ pub(crate) type Suggestion = (Vec<(Span, String)>, String, Applicability);
/// similarly named label and whether or not it is reachable.
pub(crate) type LabelSuggestion = (Ident, bool);
+#[derive(Debug)]
pub(crate) enum SuggestionTarget {
/// The target has a similar name as the name used by the programmer (probably a typo)
SimilarlyNamed,
@@ -54,6 +55,7 @@ pub(crate) enum SuggestionTarget {
SingleItem,
}
+#[derive(Debug)]
pub(crate) struct TypoSuggestion {
pub candidate: Symbol,
pub res: Res,
@@ -70,6 +72,7 @@ impl TypoSuggestion {
}
/// A free importable items suggested in case of resolution failure.
+#[derive(Debug, Clone)]
pub(crate) struct ImportSuggestion {
pub did: Option<DefId>,
pub descr: &'static str,
@@ -120,7 +123,7 @@ impl<'a> Resolver<'a> {
}
fn report_with_use_injections(&mut self, krate: &Crate) {
- for UseError { mut err, candidates, def_id, instead, suggestion, path } in
+ for UseError { mut err, candidates, def_id, instead, suggestion, path, is_call } in
self.use_injections.drain(..)
{
let (span, found_use) = if let Some(def_id) = def_id.as_local() {
@@ -128,6 +131,7 @@ impl<'a> Resolver<'a> {
} else {
(None, FoundUse::No)
};
+
if !candidates.is_empty() {
show_candidates(
&self.session,
@@ -137,13 +141,18 @@ impl<'a> Resolver<'a> {
&candidates,
if instead { Instead::Yes } else { Instead::No },
found_use,
- IsPattern::No,
+ DiagnosticMode::Normal,
path,
);
+ err.emit();
} else if let Some((span, msg, sugg, appl)) = suggestion {
err.span_suggestion(span, msg, sugg, appl);
+ err.emit();
+ } else if let [segment] = path.as_slice() && is_call {
+ err.stash(segment.ident.span, rustc_errors::StashKey::CallIntoMethod);
+ } else {
+ err.emit();
}
- err.emit();
}
}
@@ -475,11 +484,12 @@ impl<'a> Resolver<'a> {
module: Module<'a>,
names: &mut Vec<TypoSuggestion>,
filter_fn: &impl Fn(Res) -> bool,
+ ctxt: Option<SyntaxContext>,
) {
for (key, resolution) in self.resolutions(module).borrow().iter() {
if let Some(binding) = resolution.borrow().binding {
let res = binding.res();
- if filter_fn(res) {
+ if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) {
names.push(TypoSuggestion::typo_from_res(key.ident.name, res));
}
}
@@ -511,24 +521,18 @@ impl<'a> Resolver<'a> {
let sm = self.session.source_map();
let def_id = match outer_res {
- Res::SelfTy { trait_: maybe_trait_defid, alias_to: maybe_impl_defid } => {
- if let Some(impl_span) =
- maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id))
- {
+ Res::SelfTyParam { .. } => {
+ err.span_label(span, "can't use `Self` here");
+ return err;
+ }
+ Res::SelfTyAlias { alias_to: def_id, .. } => {
+ if let Some(impl_span) = self.opt_span(def_id) {
err.span_label(
reduce_impl_span_to_impl_keyword(sm, impl_span),
"`Self` type implicitly declared here, by this `impl`",
);
}
- match (maybe_trait_defid, maybe_impl_defid) {
- (Some(_), None) => {
- err.span_label(span, "can't use `Self` here");
- }
- (_, Some(_)) => {
- err.span_label(span, "use a type here instead");
- }
- (None, None) => bug!("`impl` without trait nor type?"),
- }
+ err.span_label(span, "use a type here instead");
return err;
}
Res::Def(DefKind::TyParam, def_id) => {
@@ -545,8 +549,9 @@ impl<'a> Resolver<'a> {
}
_ => {
bug!(
- "GenericParamsFromOuterFunction should only be used with Res::SelfTy, \
- DefKind::TyParam or DefKind::ConstParam"
+ "GenericParamsFromOuterFunction should only be used with \
+ Res::SelfTyParam, Res::SelfTyAlias, DefKind::TyParam or \
+ DefKind::ConstParam"
);
}
};
@@ -696,7 +701,7 @@ impl<'a> Resolver<'a> {
&import_suggestions,
Instead::No,
FoundUse::Yes,
- IsPattern::Yes,
+ DiagnosticMode::Pattern,
vec![],
);
}
@@ -1046,6 +1051,19 @@ impl<'a> Resolver<'a> {
err.span_label(trait_item_span, "item in trait");
err
}
+ ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => {
+ let mut err = struct_span_err!(
+ self.session,
+ span,
+ E0201,
+ "duplicate definitions with name `{}`:",
+ name,
+ );
+ err.span_label(old_span, "previous definition here");
+ err.span_label(trait_item_span, "item in trait");
+ err.span_label(span, "duplicate definition");
+ err
+ }
ResolutionError::InvalidAsmSym => {
let mut err = self.session.struct_span_err(span, "invalid `sym` operand");
err.span_label(span, "is a local variable");
@@ -1166,10 +1184,10 @@ impl<'a> Resolver<'a> {
Scope::CrateRoot => {
let root_ident = Ident::new(kw::PathRoot, ident.span);
let root_module = this.resolve_crate_root(root_ident);
- this.add_module_candidates(root_module, &mut suggestions, filter_fn);
+ this.add_module_candidates(root_module, &mut suggestions, filter_fn, None);
}
Scope::Module(module, _) => {
- this.add_module_candidates(module, &mut suggestions, filter_fn);
+ this.add_module_candidates(module, &mut suggestions, filter_fn, None);
}
Scope::MacroUsePrelude => {
suggestions.extend(this.macro_use_prelude.iter().filter_map(
@@ -1206,7 +1224,7 @@ impl<'a> Resolver<'a> {
Scope::StdLibPrelude => {
if let Some(prelude) = this.prelude {
let mut tmp_suggestions = Vec::new();
- this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn);
+ this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn, None);
suggestions.extend(
tmp_suggestions
.into_iter()
@@ -1479,7 +1497,7 @@ impl<'a> Resolver<'a> {
&import_suggestions,
Instead::No,
FoundUse::Yes,
- IsPattern::No,
+ DiagnosticMode::Normal,
vec![],
);
@@ -2440,12 +2458,34 @@ enum FoundUse {
No,
}
-/// Whether a binding is part of a pattern or an expression. Used for diagnostics.
-enum IsPattern {
+/// Whether a binding is part of a pattern or a use statement. Used for diagnostics.
+enum DiagnosticMode {
+ Normal,
/// The binding is part of a pattern
- Yes,
- /// The binding is part of an expression
- No,
+ Pattern,
+ /// The binding is part of a use statement
+ Import,
+}
+
+pub(crate) fn import_candidates(
+ session: &Session,
+ source_span: &IndexVec<LocalDefId, Span>,
+ err: &mut Diagnostic,
+ // This is `None` if all placement locations are inside expansions
+ use_placement_span: Option<Span>,
+ candidates: &[ImportSuggestion],
+) {
+ show_candidates(
+ session,
+ source_span,
+ err,
+ use_placement_span,
+ candidates,
+ Instead::Yes,
+ FoundUse::Yes,
+ DiagnosticMode::Import,
+ vec![],
+ );
}
/// When an entity with a given name is not available in scope, we search for
@@ -2460,7 +2500,7 @@ fn show_candidates(
candidates: &[ImportSuggestion],
instead: Instead,
found_use: FoundUse,
- is_pattern: IsPattern,
+ mode: DiagnosticMode,
path: Vec<Segment>,
) {
if candidates.is_empty() {
@@ -2495,7 +2535,7 @@ fn show_candidates(
};
let instead = if let Instead::Yes = instead { " instead" } else { "" };
- let mut msg = if let IsPattern::Yes = is_pattern {
+ let mut msg = if let DiagnosticMode::Pattern = mode {
format!(
"if you meant to match on {}{}{}, use the full path in the pattern",
kind, instead, name
@@ -2508,19 +2548,25 @@ fn show_candidates(
err.note(note);
}
- if let (IsPattern::Yes, Some(span)) = (is_pattern, use_placement_span) {
- err.span_suggestions(
- span,
- &msg,
- accessible_path_strings.into_iter().map(|a| a.0),
- Applicability::MaybeIncorrect,
- );
- } else if let Some(span) = use_placement_span {
+ if let Some(span) = use_placement_span {
+ let add_use = match mode {
+ DiagnosticMode::Pattern => {
+ err.span_suggestions(
+ span,
+ &msg,
+ accessible_path_strings.into_iter().map(|a| a.0),
+ Applicability::MaybeIncorrect,
+ );
+ return;
+ }
+ DiagnosticMode::Import => "",
+ DiagnosticMode::Normal => "use ",
+ };
for candidate in &mut accessible_path_strings {
// produce an additional newline to separate the new use statement
// from the directly following item.
let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" };
- candidate.0 = format!("use {};\n{}", &candidate.0, additional_newline);
+ candidate.0 = format!("{}{};\n{}", add_use, &candidate.0, additional_newline);
}
err.span_suggestions(
@@ -2550,11 +2596,14 @@ fn show_candidates(
err.note(&msg);
}
- } else {
+ } else if !matches!(mode, DiagnosticMode::Import) {
assert!(!inaccessible_path_strings.is_empty());
- let prefix =
- if let IsPattern::Yes = is_pattern { "you might have meant to match on " } else { "" };
+ let prefix = if let DiagnosticMode::Pattern = mode {
+ "you might have meant to match on "
+ } else {
+ ""
+ };
if inaccessible_path_strings.len() == 1 {
let (name, descr, def_id, note) = &inaccessible_path_strings[0];
let msg = format!(
@@ -2562,7 +2611,7 @@ fn show_candidates(
prefix,
descr,
name,
- if let IsPattern::Yes = is_pattern { ", which" } else { "" }
+ if let DiagnosticMode::Pattern = mode { ", which" } else { "" }
);
if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
new file mode 100644
index 000000000..c40669ac9
--- /dev/null
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -0,0 +1,188 @@
+use crate::{ImportKind, NameBindingKind, Resolver};
+use rustc_ast::ast;
+use rustc_ast::visit;
+use rustc_ast::visit::Visitor;
+use rustc_ast::Crate;
+use rustc_ast::EnumDef;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def_id::CRATE_DEF_ID;
+use rustc_middle::middle::privacy::Level;
+use rustc_middle::ty::{DefIdTree, Visibility};
+
+pub struct EffectiveVisibilitiesVisitor<'r, 'a> {
+ r: &'r mut Resolver<'a>,
+ changed: bool,
+}
+
+impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
+ /// Fills the `Resolver::effective_visibilities` table with public & exported items
+ /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
+ /// need access to a TyCtxt for that.
+ pub fn compute_effective_visibilities<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
+ let mut visitor = EffectiveVisibilitiesVisitor { r, changed: false };
+
+ visitor.update(CRATE_DEF_ID, Visibility::Public, CRATE_DEF_ID, Level::Direct);
+ visitor.set_bindings_effective_visibilities(CRATE_DEF_ID);
+
+ while visitor.changed {
+ visitor.reset();
+ visit::walk_crate(&mut visitor, krate);
+ }
+
+ info!("resolve::effective_visibilities: {:#?}", r.effective_visibilities);
+ }
+
+ fn reset(&mut self) {
+ self.changed = false;
+ }
+
+ /// Update effective visibilities of bindings in the given module,
+ /// including their whole reexport chains.
+ fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) {
+ assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
+ let module = self.r.get_module(module_id.to_def_id()).unwrap();
+ let resolutions = self.r.resolutions(module);
+
+ for (_, name_resolution) in resolutions.borrow().iter() {
+ if let Some(mut binding) = name_resolution.borrow().binding() && !binding.is_ambiguity() {
+ // Set the given effective visibility level to `Level::Direct` and
+ // sets the rest of the `use` chain to `Level::Reexported` until
+ // we hit the actual exported item.
+
+ // FIXME: tag and is_public() condition should be removed, but assertions occur.
+ let tag = if binding.is_import() { Level::Reexported } else { Level::Direct };
+ if binding.vis.is_public() {
+ let mut prev_parent_id = module_id;
+ let mut level = Level::Direct;
+ while let NameBindingKind::Import { binding: nested_binding, import, .. } =
+ binding.kind
+ {
+ let mut update = |node_id| self.update(
+ self.r.local_def_id(node_id),
+ binding.vis.expect_local(),
+ prev_parent_id,
+ level,
+ );
+ // In theory all the import IDs have individual visibilities and effective
+ // visibilities, but in practice these IDs go straigth to HIR where all
+ // their few uses assume that their (effective) visibility applies to the
+ // whole syntactic `use` item. So we update them all to the maximum value
+ // among the potential individual effective visibilities. Maybe HIR for
+ // imports shouldn't use three IDs at all.
+ update(import.id);
+ if let ImportKind::Single { additional_ids, .. } = import.kind {
+ update(additional_ids.0);
+ update(additional_ids.1);
+ }
+
+ level = Level::Reexported;
+ prev_parent_id = self.r.local_def_id(import.id);
+ binding = nested_binding;
+ }
+ }
+
+ if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
+ self.update(def_id, binding.vis.expect_local(), module_id, tag);
+ }
+ }
+ }
+ }
+
+ fn update(
+ &mut self,
+ def_id: LocalDefId,
+ nominal_vis: Visibility,
+ parent_id: LocalDefId,
+ tag: Level,
+ ) {
+ let module_id = self
+ .r
+ .get_nearest_non_block_module(def_id.to_def_id())
+ .nearest_parent_mod()
+ .expect_local();
+ if nominal_vis == Visibility::Restricted(module_id)
+ || self.r.visibilities[&parent_id] == Visibility::Restricted(module_id)
+ {
+ return;
+ }
+ let mut effective_visibilities = std::mem::take(&mut self.r.effective_visibilities);
+ self.changed |= effective_visibilities.update(
+ def_id,
+ nominal_vis,
+ || Visibility::Restricted(module_id),
+ parent_id,
+ tag,
+ &*self.r,
+ );
+ self.r.effective_visibilities = effective_visibilities;
+ }
+}
+
+impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
+ fn visit_item(&mut self, item: &'ast ast::Item) {
+ let def_id = self.r.local_def_id(item.id);
+ // Update effective visibilities of nested items.
+ // If it's a mod, also make the visitor walk all of its items
+ match item.kind {
+ // Resolved in rustc_privacy when types are available
+ ast::ItemKind::Impl(..) => return,
+
+ // Should be unreachable at this stage
+ ast::ItemKind::MacCall(..) => panic!(
+ "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
+ ),
+
+ // Foreign modules inherit level from parents.
+ ast::ItemKind::ForeignMod(..) => {
+ let parent_id = self.r.local_parent(def_id);
+ self.update(def_id, Visibility::Public, parent_id, Level::Direct);
+ }
+
+ // Only exported `macro_rules!` items are public, but they always are
+ ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => {
+ let parent_id = self.r.local_parent(def_id);
+ let vis = self.r.visibilities[&def_id];
+ self.update(def_id, vis, parent_id, Level::Direct);
+ }
+
+ ast::ItemKind::Mod(..) => {
+ self.set_bindings_effective_visibilities(def_id);
+ visit::walk_item(self, item);
+ }
+
+ ast::ItemKind::Enum(EnumDef { ref variants }, _) => {
+ self.set_bindings_effective_visibilities(def_id);
+ for variant in variants {
+ let variant_def_id = self.r.local_def_id(variant.id);
+ for field in variant.data.fields() {
+ let field_def_id = self.r.local_def_id(field.id);
+ let vis = self.r.visibilities[&field_def_id];
+ self.update(field_def_id, vis, variant_def_id, Level::Direct);
+ }
+ }
+ }
+
+ ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
+ for field in def.fields() {
+ let field_def_id = self.r.local_def_id(field.id);
+ let vis = self.r.visibilities[&field_def_id];
+ self.update(field_def_id, vis, def_id, Level::Direct);
+ }
+ }
+
+ ast::ItemKind::Trait(..) => {
+ self.set_bindings_effective_visibilities(def_id);
+ }
+
+ ast::ItemKind::ExternCrate(..)
+ | ast::ItemKind::Use(..)
+ | ast::ItemKind::Static(..)
+ | ast::ItemKind::Const(..)
+ | ast::ItemKind::GlobalAsm(..)
+ | ast::ItemKind::TyAlias(..)
+ | ast::ItemKind::TraitAlias(..)
+ | ast::ItemKind::MacroDef(..)
+ | ast::ItemKind::Fn(..) => return,
+ }
+ }
+}
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 2287aa1eb..e0542d547 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -1162,7 +1162,7 @@ impl<'a> Resolver<'a> {
return Res::Err;
}
}
- Res::Def(DefKind::TyParam, _) | Res::SelfTy { .. } => {
+ Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => {
for rib in ribs {
let has_generic_params: HasGenericParams = match rib.kind {
NormalRibKind
@@ -1182,11 +1182,21 @@ impl<'a> Resolver<'a> {
if !(trivial == ConstantHasGenerics::Yes
|| features.generic_const_exprs)
{
- // 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 concrete later on.
- if let Res::SelfTy { trait_, alias_to: Some((def, _)) } = res {
- res = Res::SelfTy { trait_, alias_to: Some((def, true)) }
+ // 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
+ // concrete later on.
+ if let Res::SelfTyAlias {
+ alias_to: def,
+ forbid_generic: _,
+ is_trait_impl,
+ } = res
+ {
+ res = Res::SelfTyAlias {
+ alias_to: def,
+ forbid_generic: true,
+ is_trait_impl,
+ }
} else {
if let Some(span) = finalize {
self.report_error(
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index c133c272b..f2cc50c19 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -1,9 +1,9 @@
//! A bunch of methods and structures more or less related to resolving imports.
-use crate::diagnostics::Suggestion;
+use crate::diagnostics::{import_candidates, Suggestion};
use crate::Determinacy::{self, *};
-use crate::Namespace::{MacroNS, TypeNS};
-use crate::{module_to_string, names_to_string};
+use crate::Namespace::*;
+use crate::{module_to_string, names_to_string, ImportSuggestion};
use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment};
use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet};
use crate::{NameBinding, NameBindingKind, PathResult};
@@ -252,7 +252,7 @@ impl<'a> Resolver<'a> {
self.set_binding_parent_module(binding, module);
self.update_resolution(module, key, |this, resolution| {
if let Some(old_binding) = resolution.binding {
- if res == Res::Err {
+ if res == Res::Err && old_binding.res() != Res::Err {
// Do not override real bindings with `Res::Err`s from error recovery.
return Ok(());
}
@@ -381,6 +381,7 @@ struct UnresolvedImportError {
label: Option<String>,
note: Option<String>,
suggestion: Option<Suggestion>,
+ candidate: Option<Vec<ImportSuggestion>>,
}
pub struct ImportResolver<'a, 'b> {
@@ -472,6 +473,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
label: None,
note: None,
suggestion: None,
+ candidate: None,
};
if path.contains("::") {
errors.push((path, err))
@@ -522,6 +524,16 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
}
diag.multipart_suggestion(&msg, suggestions, applicability);
}
+
+ if let Some(candidate) = &err.candidate {
+ import_candidates(
+ self.r.session,
+ &self.r.source_span,
+ &mut diag,
+ Some(err.span),
+ &candidate,
+ )
+ }
}
diag.emit();
@@ -639,6 +651,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
Some(finalize),
ignore_binding,
);
+
let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
import.vis.set(orig_vis);
let module = match path_res {
@@ -681,12 +694,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
String::from("a similar path exists"),
Applicability::MaybeIncorrect,
)),
+ candidate: None,
},
None => UnresolvedImportError {
span,
label: Some(label),
note: None,
suggestion,
+ candidate: None,
},
};
return Some(err);
@@ -729,6 +744,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
label: Some(String::from("cannot glob-import a module into itself")),
note: None,
suggestion: None,
+ candidate: None,
});
}
}
@@ -894,11 +910,19 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
}
};
+ let parent_suggestion =
+ self.r.lookup_import_candidates(ident, TypeNS, &import.parent_scope, |_| true);
+
Some(UnresolvedImportError {
span: import.span,
label: Some(label),
note,
suggestion,
+ candidate: if !parent_suggestion.is_empty() {
+ Some(parent_suggestion)
+ } else {
+ None
+ },
})
} else {
// `resolve_ident_in_module` reported a privacy error.
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index d8d82e125..00eb768ad 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -19,7 +19,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_errors::DiagnosticId;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate};
use rustc_middle::middle::resolve_lifetime::Set1;
use rustc_middle::ty::DefIdTree;
@@ -35,7 +35,6 @@ use std::collections::{hash_map::Entry, BTreeSet};
use std::mem::{replace, take};
mod diagnostics;
-pub(crate) mod lifetimes;
type Res = def::Res<NodeId>;
@@ -226,22 +225,14 @@ enum LifetimeUseSet {
#[derive(Copy, Clone, Debug)]
enum LifetimeRibKind {
- /// This rib acts as a barrier to forbid reference to lifetimes of a parent item.
- Item,
-
+ // -- Ribs introducing named lifetimes
+ //
/// This rib declares generic parameters.
+ /// Only for this kind the `LifetimeRib::bindings` field can be non-empty.
Generics { binder: NodeId, span: Span, kind: LifetimeBinderKind },
- /// 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,
-
- /// 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,
-
+ // -- Ribs introducing unnamed lifetimes
+ //
/// Create a new anonymous lifetime parameter and reference it.
///
/// If `report_in_path`, report an error when encountering lifetime elision in a path:
@@ -258,16 +249,31 @@ enum LifetimeRibKind {
/// ```
AnonymousCreateParameter { binder: NodeId, report_in_path: bool },
+ /// Replace all anonymous lifetimes by provided lifetime.
+ Elided(LifetimeRes),
+
+ // -- Barrier ribs that stop lifetime lookup, or continue it but produce an error later.
+ //
/// Give a hard error when either `&` or `'_` is written. Used to
/// rule out things like `where T: Foo<'_>`. Does not imply an
/// error on default object bounds (e.g., `Box<dyn Foo>`).
AnonymousReportError,
- /// Replace all anonymous lifetimes by provided lifetime.
- Elided(LifetimeRes),
-
/// 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,
+
+ /// 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,
+
+ /// This rib acts as a barrier to forbid reference to lifetimes of a parent item.
+ Item,
}
#[derive(Copy, Clone, Debug)]
@@ -415,7 +421,8 @@ impl<'a> PathSource<'a> {
| DefKind::ForeignTy,
_,
) | Res::PrimTy(..)
- | Res::SelfTy { .. }
+ | Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. }
),
PathSource::Trait(AliasPossibility::No) => matches!(res, Res::Def(DefKind::Trait, _)),
PathSource::Trait(AliasPossibility::Maybe) => {
@@ -449,7 +456,8 @@ impl<'a> PathSource<'a> {
| DefKind::TyAlias
| DefKind::AssocTy,
_,
- ) | Res::SelfTy { .. }
+ ) | Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. }
),
PathSource::TraitItem(ns) => match res {
Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) if ns == ValueNS => true,
@@ -517,6 +525,9 @@ struct DiagnosticMetadata<'ast> {
/// Used to detect possible `if let` written without `let` and to provide structured suggestion.
in_if_condition: Option<&'ast Expr>,
+ /// Used to detect possible new binding written without `let` and to provide structured suggestion.
+ in_assignment: Option<&'ast Expr>,
+
/// If we are currently in a trait object definition. Used to point at the bounds when
/// encountering a struct or enum.
current_trait_object: Option<&'ast [ast::GenericBound]>,
@@ -641,8 +652,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
// Check whether we should interpret this as a bare trait object.
if qself.is_none()
&& let Some(partial_res) = self.r.partial_res_map.get(&ty.id)
- && partial_res.unresolved_segments() == 0
- && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
+ && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res()
{
// This path is actually a bare trait object. In case of a bare `Fn`-trait
// object with anonymous lifetimes, we need this rib to correctly place the
@@ -749,35 +759,31 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
match foreign_item.kind {
ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
- self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
- this.with_generic_param_rib(
- &generics.params,
- ItemRibKind(HasGenericParams::Yes(generics.span)),
- LifetimeRibKind::Generics {
- binder: foreign_item.id,
- kind: LifetimeBinderKind::Item,
- span: generics.span,
- },
- |this| visit::walk_foreign_item(this, foreign_item),
- )
- });
+ self.with_generic_param_rib(
+ &generics.params,
+ ItemRibKind(HasGenericParams::Yes(generics.span)),
+ LifetimeRibKind::Generics {
+ binder: foreign_item.id,
+ kind: LifetimeBinderKind::Item,
+ span: generics.span,
+ },
+ |this| visit::walk_foreign_item(this, foreign_item),
+ );
}
ForeignItemKind::Fn(box Fn { ref generics, .. }) => {
- self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
- this.with_generic_param_rib(
- &generics.params,
- ItemRibKind(HasGenericParams::Yes(generics.span)),
- LifetimeRibKind::Generics {
- binder: foreign_item.id,
- kind: LifetimeBinderKind::Function,
- span: generics.span,
- },
- |this| visit::walk_foreign_item(this, foreign_item),
- )
- });
+ self.with_generic_param_rib(
+ &generics.params,
+ ItemRibKind(HasGenericParams::Yes(generics.span)),
+ LifetimeRibKind::Generics {
+ binder: foreign_item.id,
+ kind: LifetimeBinderKind::Function,
+ span: generics.span,
+ },
+ |this| visit::walk_foreign_item(this, foreign_item),
+ );
}
ForeignItemKind::Static(..) => {
- self.with_item_rib(|this| {
+ self.with_static_rib(|this| {
visit::walk_foreign_item(this, foreign_item);
});
}
@@ -806,7 +812,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
sig.decl.has_self(),
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(),
+ );
},
);
return;
@@ -848,41 +859,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
},
);
- // Construct the list of in-scope lifetime parameters for async lowering.
- // We include all lifetime parameters, either named or "Fresh".
- // The order of those parameters does not matter, as long as it is
- // deterministic.
- if let Some((async_node_id, _)) = async_node_id {
- let mut extra_lifetime_params = this
- .r
- .extra_lifetime_params_map
- .get(&fn_id)
- .cloned()
- .unwrap_or_default();
- for rib in this.lifetime_ribs.iter().rev() {
- extra_lifetime_params.extend(
- rib.bindings
- .iter()
- .map(|(&ident, &(node_id, res))| (ident, node_id, res)),
- );
- match rib.kind {
- LifetimeRibKind::Item => break,
- LifetimeRibKind::AnonymousCreateParameter {
- binder, ..
- } => {
- if let Some(earlier_fresh) =
- this.r.extra_lifetime_params_map.get(&binder)
- {
- extra_lifetime_params.extend(earlier_fresh);
- }
- }
- _ => {}
- }
- }
- this.r
- .extra_lifetime_params_map
- .insert(async_node_id, extra_lifetime_params);
- }
+ this.record_lifetime_params_for_async(fn_id, async_node_id);
if let Some(body) = body {
// Ignore errors in function bodies if this is rustdoc
@@ -1421,9 +1398,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
return self.resolve_anonymous_lifetime(lifetime, false);
}
- let mut indices = (0..self.lifetime_ribs.len()).rev();
- for i in &mut indices {
- let rib = &self.lifetime_ribs[i];
+ let mut lifetime_rib_iter = self.lifetime_ribs.iter().rev();
+ while let Some(rib) = lifetime_rib_iter.next() {
let normalized_ident = ident.normalize_to_macros_2_0();
if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) {
self.record_lifetime_res(lifetime.id, res, LifetimeElisionCandidate::Named);
@@ -1453,9 +1429,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
} else {
LifetimeUseSet::Many
}),
- LifetimeRibKind::Generics { .. }
- | LifetimeRibKind::ConstGeneric
- | LifetimeRibKind::AnonConst => None,
+ LifetimeRibKind::Generics { .. } => None,
+ LifetimeRibKind::ConstGeneric | LifetimeRibKind::AnonConst => {
+ span_bug!(ident.span, "unexpected rib kind: {:?}", rib.kind)
+ }
})
.unwrap_or(LifetimeUseSet::Many);
debug!(?use_ctxt, ?use_set);
@@ -1490,13 +1467,16 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
);
return;
}
- _ => {}
+ LifetimeRibKind::AnonymousCreateParameter { .. }
+ | LifetimeRibKind::Elided(_)
+ | LifetimeRibKind::Generics { .. }
+ | LifetimeRibKind::ElisionFailure
+ | LifetimeRibKind::AnonymousReportError => {}
}
}
let mut outer_res = None;
- for i in indices {
- let rib = &self.lifetime_ribs[i];
+ for rib in lifetime_rib_iter {
let normalized_ident = ident.normalize_to_macros_2_0();
if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) {
outer_res = Some(outer);
@@ -1523,8 +1503,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
count: 1,
};
let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
- for i in (0..self.lifetime_ribs.len()).rev() {
- let rib = &mut self.lifetime_ribs[i];
+ for rib in self.lifetime_ribs.iter().rev() {
debug!(?rib.kind);
match rib.kind {
LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
@@ -1564,9 +1543,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
return;
}
LifetimeRibKind::Item => break,
- LifetimeRibKind::Generics { .. }
- | LifetimeRibKind::ConstGeneric
- | LifetimeRibKind::AnonConst => {}
+ LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {}
+ LifetimeRibKind::AnonConst => {
+ // There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`.
+ span_bug!(lifetime.ident.span, "unexpected rib kind: {:?}", rib.kind)
+ }
}
}
self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
@@ -1781,9 +1762,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
break;
}
- LifetimeRibKind::Generics { .. }
- | LifetimeRibKind::ConstGeneric
- | LifetimeRibKind::AnonConst => {}
+ LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {}
+ LifetimeRibKind::AnonConst => {
+ // There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`.
+ span_bug!(elided_lifetime_span, "unexpected rib kind: {:?}", rib.kind)
+ }
}
}
@@ -1896,9 +1879,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
for (index, (pat, ty)) in inputs.enumerate() {
debug!(?pat, ?ty);
- if let Some(pat) = pat {
- self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
- }
+ self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
+ if let Some(pat) = pat {
+ this.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
+ }
+ });
// Record elision candidates only for this parameter.
debug_assert_matches!(self.lifetime_elision_candidates, None);
@@ -1992,11 +1977,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
match ty.kind {
TyKind::ImplicitSelf => true,
TyKind::Path(None, _) => {
- let path_res = self.r.partial_res_map[&ty.id].base_res();
- if let Res::SelfTy { .. } = path_res {
+ let path_res = self.r.partial_res_map[&ty.id].full_res();
+ if let Some(Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }) = path_res {
return true;
}
- Some(path_res) == self.impl_self
+ self.impl_self.is_some() && path_res == self.impl_self
}
_ => false,
}
@@ -2033,7 +2018,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
None
}
})
- .map(|res| res.base_res())
+ .and_then(|res| res.full_res())
.filter(|res| {
// Permit the types that unambiguously always
// result in the same type constructor being used
@@ -2114,7 +2099,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|this| {
let item_def_id = this.r.local_def_id(item.id).to_def_id();
this.with_self_rib(
- Res::SelfTy { trait_: None, alias_to: Some((item_def_id, false)) },
+ Res::SelfTyAlias {
+ alias_to: item_def_id,
+ forbid_generic: false,
+ is_trait_impl: false,
+ },
|this| {
visit::walk_item(this, item);
},
@@ -2228,14 +2217,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
},
|this| {
let local_def_id = this.r.local_def_id(item.id).to_def_id();
- this.with_self_rib(
- Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
- |this| {
- this.visit_generics(generics);
- walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits);
- this.resolve_trait_items(items);
- },
- );
+ this.with_self_rib(Res::SelfTyParam { trait_: local_def_id }, |this| {
+ this.visit_generics(generics);
+ walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits);
+ this.resolve_trait_items(items);
+ });
},
);
}
@@ -2252,13 +2238,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
},
|this| {
let local_def_id = this.r.local_def_id(item.id).to_def_id();
- this.with_self_rib(
- Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
- |this| {
- this.visit_generics(generics);
- walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
- },
- );
+ this.with_self_rib(Res::SelfTyParam { trait_: local_def_id }, |this| {
+ this.visit_generics(generics);
+ walk_list!(this, visit_param_bound, bounds, BoundKind::Bound);
+ });
},
);
}
@@ -2270,7 +2253,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}
ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => {
- self.with_item_rib(|this| {
+ self.with_static_rib(|this| {
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
this.visit_ty(ty);
});
@@ -2465,11 +2448,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.label_ribs.pop();
}
- fn with_item_rib(&mut self, f: impl FnOnce(&mut Self)) {
+ fn with_static_rib(&mut self, f: impl FnOnce(&mut Self)) {
let kind = ItemRibKind(HasGenericParams::No);
- self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
- this.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
- })
+ self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
}
// HACK(min_const_generics,const_evaluatable_unchecked): We
@@ -2562,7 +2543,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
AssocItemKind::Fn(box Fn { generics, .. }) => {
walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
}
- AssocItemKind::TyAlias(box TyAlias { generics, .. }) => self
+ AssocItemKind::Type(box TyAlias { generics, .. }) => self
.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
walk_assoc_item(this, generics, LifetimeBinderKind::Item, item)
}),
@@ -2595,7 +2576,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
Finalize::new(trait_ref.ref_id, trait_ref.path.span),
);
self.diagnostic_metadata.currently_processing_impl_trait = None;
- if let Some(def_id) = res.base_res().opt_def_id() {
+ if let Some(def_id) = res.expect_full_res().opt_def_id() {
new_id = Some(def_id);
new_val = Some((self.r.expect_module(def_id), trait_ref.clone()));
}
@@ -2640,7 +2621,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
},
|this| {
// Dummy self type for better errors if `Self` is used in the trait path.
- this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
+ this.with_self_rib(Res::SelfTyParam { trait_: LOCAL_CRATE.as_def_id() }, |this| {
this.with_lifetime_rib(
LifetimeRibKind::AnonymousCreateParameter {
binder: item_id,
@@ -2664,9 +2645,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}
let item_def_id = item_def_id.to_def_id();
- let res = Res::SelfTy {
- trait_: trait_id,
- alias_to: Some((item_def_id, false)),
+ let res = Res::SelfTyAlias {
+ alias_to: item_def_id,
+ forbid_generic: false,
+ is_trait_impl: trait_id.is_some()
};
this.with_self_rib(res, |this| {
if let Some(trait_ref) = opt_trait_reference.as_ref() {
@@ -2682,8 +2664,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
this.with_current_self_type(self_type, |this| {
this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
+ let mut seen_trait_items = Default::default();
for item in impl_items {
- this.resolve_impl_item(&**item);
+ this.resolve_impl_item(&**item, &mut seen_trait_items);
}
});
});
@@ -2697,7 +2680,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
);
}
- fn resolve_impl_item(&mut self, item: &'ast AssocItem) {
+ fn resolve_impl_item(
+ &mut self,
+ item: &'ast AssocItem,
+ seen_trait_items: &mut FxHashMap<DefId, Span>,
+ ) {
use crate::ResolutionError::*;
match &item.kind {
AssocItemKind::Const(_, ty, default) => {
@@ -2710,6 +2697,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
&item.kind,
ValueNS,
item.span,
+ seen_trait_items,
|i, s, c| ConstNotMemberOfTrait(i, s, c),
);
@@ -2750,6 +2738,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
&item.kind,
ValueNS,
item.span,
+ seen_trait_items,
|i, s, c| MethodNotMemberOfTrait(i, s, c),
);
@@ -2757,8 +2746,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
},
);
}
- AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
- debug!("resolve_implementation AssocItemKind::TyAlias");
+ AssocItemKind::Type(box TyAlias { generics, .. }) => {
+ debug!("resolve_implementation AssocItemKind::Type");
// We also need a new scope for the impl item type parameters.
self.with_generic_param_rib(
&generics.params,
@@ -2778,6 +2767,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
&item.kind,
TypeNS,
item.span,
+ seen_trait_items,
|i, s, c| TypeNotMemberOfTrait(i, s, c),
);
@@ -2799,6 +2789,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
kind: &AssocItemKind,
ns: Namespace,
span: Span,
+ seen_trait_items: &mut FxHashMap<DefId, Span>,
err: F,
) where
F: FnOnce(Ident, String, Option<Symbol>) -> ResolutionError<'a>,
@@ -2831,9 +2822,27 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
};
let res = binding.res();
- let Res::Def(def_kind, _) = res else { bug!() };
+ let Res::Def(def_kind, id_in_trait) = res else { bug!() };
+
+ match seen_trait_items.entry(id_in_trait) {
+ Entry::Occupied(entry) => {
+ self.report_error(
+ span,
+ ResolutionError::TraitImplDuplicate {
+ name: ident.name,
+ old_span: *entry.get(),
+ trait_item_span: binding.span,
+ },
+ );
+ return;
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(span);
+ }
+ };
+
match (def_kind, kind) {
- (DefKind::AssocTy, AssocItemKind::TyAlias(..))
+ (DefKind::AssocTy, AssocItemKind::Type(..))
| (DefKind::AssocFn, AssocItemKind::Fn(..))
| (DefKind::AssocConst, AssocItemKind::Const(..)) => {
self.r.record_partial_res(id, PartialRes::new(res));
@@ -2847,7 +2856,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
let (code, kind) = match kind {
AssocItemKind::Const(..) => (rustc_errors::error_code!(E0323), "const"),
AssocItemKind::Fn(..) => (rustc_errors::error_code!(E0324), "method"),
- AssocItemKind::TyAlias(..) => (rustc_errors::error_code!(E0325), "type"),
+ AssocItemKind::Type(..) => (rustc_errors::error_code!(E0325), "type"),
AssocItemKind::MacCall(..) => span_bug!(span, "unexpanded macro"),
};
let trait_path = path_names_to_string(path);
@@ -2865,10 +2874,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
fn resolve_params(&mut self, params: &'ast [Param]) {
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
- for Param { pat, ty, .. } in params {
- self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
+ self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
+ for Param { pat, .. } in params {
+ this.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
+ }
+ });
+ for Param { ty, .. } in params {
self.visit_ty(ty);
- debug!("(resolving function / closure) recorded parameter");
}
}
@@ -2923,7 +2935,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}
fn is_base_res_local(&self, nid: NodeId) -> bool {
- matches!(self.r.partial_res_map.get(&nid).map(|res| res.base_res()), Some(Res::Local(..)))
+ matches!(
+ self.r.partial_res_map.get(&nid).map(|res| res.expect_full_res()),
+ Some(Res::Local(..))
+ )
}
/// Checks that all of the arms in an or-pattern have exactly the
@@ -3326,6 +3341,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
instead,
suggestion,
path: path.into(),
+ is_call: source.is_call(),
});
}
@@ -3390,6 +3406,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
instead: false,
suggestion: None,
path: path.into(),
+ is_call: source.is_call(),
});
} else {
err.cancel();
@@ -3408,12 +3425,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
source.defer_to_typeck(),
finalize,
) {
- Ok(Some(partial_res)) if partial_res.unresolved_segments() == 0 => {
- if source.is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err
- {
+ Ok(Some(partial_res)) if let Some(res) = partial_res.full_res() => {
+ if source.is_expected(res) || res == Res::Err {
partial_res
} else {
- report_errors(self, Some(partial_res.base_res()))
+ report_errors(self, Some(res))
}
}
@@ -3621,20 +3637,21 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
};
if path.len() > 1
- && result.base_res() != Res::Err
+ && let Some(res) = result.full_res()
+ && res != Res::Err
&& path[0].ident.name != kw::PathRoot
&& path[0].ident.name != kw::DollarCrate
{
let unqualified_result = {
match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) {
- PathResult::NonModule(path_res) => path_res.base_res(),
+ PathResult::NonModule(path_res) => path_res.expect_full_res(),
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
module.res().unwrap()
}
_ => return Ok(Some(result)),
}
};
- if result.base_res() == unqualified_result {
+ if res == unqualified_result {
let lint = lint::builtin::UNUSED_QUALIFICATIONS;
self.r.lint_buffer.buffer_lint(
lint,
@@ -3828,9 +3845,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
ExprKind::Field(ref subexpression, _) => {
self.resolve_expr(subexpression, Some(expr));
}
- ExprKind::MethodCall(ref segment, ref arguments, _) => {
- let mut arguments = arguments.iter();
- self.resolve_expr(arguments.next().unwrap(), Some(expr));
+ ExprKind::MethodCall(ref segment, ref receiver, ref arguments, _) => {
+ self.resolve_expr(receiver, Some(expr));
for argument in arguments {
self.resolve_expr(argument, None);
}
@@ -3927,6 +3943,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.resolve_expr(elem, Some(expr));
self.visit_expr(idx);
}
+ ExprKind::Assign(..) => {
+ let old = self.diagnostic_metadata.in_assignment.replace(expr);
+ visit::walk_expr(self, expr);
+ self.diagnostic_metadata.in_assignment = old;
+ }
_ => {
visit::walk_expr(self, expr);
}
@@ -3962,6 +3983,41 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
Some((ident.name, ns)),
)
}
+
+ /// Construct the list of in-scope lifetime parameters for async lowering.
+ /// We include all lifetime parameters, either named or "Fresh".
+ /// The order of those parameters does not matter, as long as it is
+ /// deterministic.
+ fn record_lifetime_params_for_async(
+ &mut self,
+ fn_id: NodeId,
+ async_node_id: Option<(NodeId, Span)>,
+ ) {
+ if let Some((async_node_id, span)) = async_node_id {
+ let mut extra_lifetime_params =
+ self.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default();
+ for rib in self.lifetime_ribs.iter().rev() {
+ extra_lifetime_params.extend(
+ rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res)),
+ );
+ match rib.kind {
+ LifetimeRibKind::Item => break,
+ LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
+ if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) {
+ extra_lifetime_params.extend(earlier_fresh);
+ }
+ }
+ LifetimeRibKind::Generics { .. } => {}
+ _ => {
+ // We are in a function definition. We should only find `Generics`
+ // and `AnonymousCreateParameter` inside the innermost `Item`.
+ span_bug!(span, "unexpected rib kind: {:?}", rib.kind)
+ }
+ }
+ }
+ self.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params);
+ }
+ }
}
struct LifetimeCountVisitor<'a, 'b> {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 3b095eeeb..850f023b1 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -38,8 +38,8 @@ type Res = def::Res<ast::NodeId>;
/// A field or associated item from self type suggested in case of resolution failure.
enum AssocSuggestion {
Field,
- MethodWithSelf,
- AssocFn,
+ MethodWithSelf { called: bool },
+ AssocFn { called: bool },
AssocType,
AssocConst,
}
@@ -48,8 +48,14 @@ impl AssocSuggestion {
fn action(&self) -> &'static str {
match self {
AssocSuggestion::Field => "use the available field",
- AssocSuggestion::MethodWithSelf => "call the method with the fully-qualified path",
- AssocSuggestion::AssocFn => "call the associated function",
+ AssocSuggestion::MethodWithSelf { called: true } => {
+ "call the method with the fully-qualified path"
+ }
+ AssocSuggestion::MethodWithSelf { called: false } => {
+ "refer to the method with the fully-qualified path"
+ }
+ AssocSuggestion::AssocFn { called: true } => "call the associated function",
+ AssocSuggestion::AssocFn { called: false } => "refer to the associated function",
AssocSuggestion::AssocConst => "use the associated `const`",
AssocSuggestion::AssocType => "use the associated type",
}
@@ -130,6 +136,33 @@ pub(super) enum LifetimeElisionCandidate {
Missing(MissingLifetime),
}
+/// Only used for diagnostics.
+#[derive(Debug)]
+struct BaseError {
+ msg: String,
+ fallback_label: String,
+ span: Span,
+ span_label: Option<(Span, &'static str)>,
+ could_be_expr: bool,
+ suggestion: Option<(Span, &'static str, String)>,
+}
+
+#[derive(Debug)]
+enum TypoCandidate {
+ Typo(TypoSuggestion),
+ Shadowed(Res),
+ None,
+}
+
+impl TypoCandidate {
+ fn to_opt_suggestion(self) -> Option<TypoSuggestion> {
+ match self {
+ TypoCandidate::Typo(sugg) => Some(sugg),
+ TypoCandidate::Shadowed(_) | TypoCandidate::None => None,
+ }
+ }
+}
+
impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
fn def_span(&self, def_id: DefId) -> Option<Span> {
match def_id.krate {
@@ -138,35 +171,18 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
}
}
- /// Handles error reporting for `smart_resolve_path_fragment` function.
- /// Creates base error and amends it with one short label and possibly some longer helps/notes.
- pub(crate) fn smart_resolve_report_errors(
+ fn make_base_error(
&mut self,
path: &[Segment],
span: Span,
source: PathSource<'_>,
res: Option<Res>,
- ) -> (DiagnosticBuilder<'a, ErrorGuaranteed>, Vec<ImportSuggestion>) {
- let ident_span = path.last().map_or(span, |ident| ident.ident.span);
- let ns = source.namespace();
- let is_expected = &|res| source.is_expected(res);
- let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
-
- debug!(?res, ?source);
-
+ ) -> BaseError {
// Make the base error.
- struct BaseError<'a> {
- msg: String,
- fallback_label: String,
- span: Span,
- span_label: Option<(Span, &'a str)>,
- could_be_expr: bool,
- suggestion: Option<(Span, &'a str, String)>,
- }
let mut expected = source.descr_expected();
let path_str = Segment::names_to_string(path);
let item_str = path.last().unwrap().ident;
- let base_error = if let Some(res) = res {
+ if let Some(res) = res {
BaseError {
msg: format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
fallback_label: format!("not a {expected}"),
@@ -277,8 +293,20 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
could_be_expr: false,
suggestion,
}
- };
+ }
+ }
+ /// Handles error reporting for `smart_resolve_path_fragment` function.
+ /// Creates base error and amends it with one short label and possibly some longer helps/notes.
+ pub(crate) fn smart_resolve_report_errors(
+ &mut self,
+ path: &[Segment],
+ span: Span,
+ source: PathSource<'_>,
+ res: Option<Res>,
+ ) -> (DiagnosticBuilder<'a, ErrorGuaranteed>, Vec<ImportSuggestion>) {
+ 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.session.struct_span_err_with_code(base_error.span, &base_error.msg, code);
@@ -289,41 +317,79 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
err.span_label(span, label);
}
- if let Some(sugg) = base_error.suggestion {
- err.span_suggestion_verbose(sugg.0, sugg.1, sugg.2, Applicability::MaybeIncorrect);
+ if let Some(ref sugg) = base_error.suggestion {
+ err.span_suggestion_verbose(sugg.0, sugg.1, &sugg.2, Applicability::MaybeIncorrect);
}
- if let Some(span) = self.diagnostic_metadata.current_block_could_be_bare_struct_literal {
- err.multipart_suggestion(
- "you might have meant to write a `struct` literal",
- vec![
- (span.shrink_to_lo(), "{ SomeStruct ".to_string()),
- (span.shrink_to_hi(), "}".to_string()),
- ],
- Applicability::HasPlaceholders,
- );
+ self.suggest_bare_struct_literal(&mut err);
+ self.suggest_pattern_match_with_let(&mut err, source, span);
+
+ self.suggest_self_or_self_ref(&mut err, path, span);
+ self.detect_assoct_type_constraint_meant_as_path(&mut err, &base_error);
+ if self.suggest_self_ty(&mut err, source, path, span)
+ || self.suggest_self_value(&mut err, source, path, span)
+ {
+ return (err, Vec::new());
}
- match (source, self.diagnostic_metadata.in_if_condition) {
- (
- PathSource::Expr(_),
- Some(Expr { span: expr_span, kind: ExprKind::Assign(lhs, _, _), .. }),
- ) => {
- // Icky heuristic so we don't suggest:
- // `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
- // `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
- if lhs.is_approximately_pattern() && lhs.span.contains(span) {
- err.span_suggestion_verbose(
- expr_span.shrink_to_lo(),
- "you might have meant to use pattern matching",
- "let ",
- Applicability::MaybeIncorrect,
- );
+
+ let (found, candidates) =
+ self.try_lookup_name_relaxed(&mut err, source, path, span, res, &base_error);
+ if found {
+ 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);
+ 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);
+ }
+ }
+ self.err_code_special_cases(&mut err, source, path, span);
+
+ (err, candidates)
+ }
+
+ fn detect_assoct_type_constraint_meant_as_path(
+ &self,
+ err: &mut Diagnostic,
+ base_error: &BaseError,
+ ) {
+ let Some(ty) = self.diagnostic_metadata.current_type_path else { return; };
+ let TyKind::Path(_, path) = &ty.kind else { return; };
+ for segment in &path.segments {
+ let Some(params) = &segment.args else { continue; };
+ let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else { continue; };
+ for param in &params.args {
+ let ast::AngleBracketedArg::Constraint(constraint) = param else { continue; };
+ let ast::AssocConstraintKind::Bound { bounds } = &constraint.kind else {
+ continue;
+ };
+ for bound in bounds {
+ let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)
+ = bound else
+ {
+ continue;
+ };
+ if base_error.span == trait_ref.span {
+ err.span_suggestion_verbose(
+ constraint.ident.span.between(trait_ref.span),
+ "you might have meant to write a path instead of an associated type bound",
+ "::",
+ Applicability::MachineApplicable,
+ );
+ }
}
}
- _ => {}
}
+ }
+ fn suggest_self_or_self_ref(&mut self, err: &mut Diagnostic, path: &[Segment], span: Span) {
let is_assoc_fn = self.self_type_is_available();
+ let Some(path_last_segment) = path.last() else { return };
+ let item_str = path_last_segment.ident;
// Emit help message for fake-self from other languages (e.g., `this` in Javascript).
if ["this", "my"].contains(&item_str.as_str()) && is_assoc_fn {
err.span_suggestion_short(
@@ -358,96 +424,25 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
}
}
}
+ }
- self.detect_assoct_type_constraint_meant_as_path(base_error.span, &mut err);
-
- // Emit special messages for unresolved `Self` and `self`.
- if is_self_type(path, ns) {
- err.code(rustc_errors::error_code!(E0411));
- err.span_label(
- span,
- "`Self` is only available in impls, traits, and type definitions".to_string(),
- );
- if let Some(item_kind) = self.diagnostic_metadata.current_item {
- err.span_label(
- item_kind.ident.span,
- format!(
- "`Self` not allowed in {} {}",
- item_kind.kind.article(),
- item_kind.kind.descr()
- ),
- );
- }
- return (err, Vec::new());
- }
- if is_self_value(path, ns) {
- debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
-
- err.code(rustc_errors::error_code!(E0424));
- err.span_label(span, match source {
- PathSource::Pat => "`self` value is a keyword and may not be bound to variables or shadowed",
- _ => "`self` value is a keyword only available in methods with a `self` parameter",
- });
- if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function {
- // 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()) {
- 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 {
- let (span, sugg) = fn_kind
- .decl()
- .inputs
- .get(0)
- .map(|p| (p.span.shrink_to_lo(), "&self, "))
- .unwrap_or_else(|| {
- // Try to look for the "(" after the function name, if possible.
- // This avoids placing the suggestion into the visibility specifier.
- let span = fn_kind
- .ident()
- .map_or(*span, |ident| span.with_lo(ident.span.hi()));
- (
- self.r
- .session
- .source_map()
- .span_through_char(span, '(')
- .shrink_to_hi(),
- "&self",
- )
- });
- err.span_suggestion_verbose(
- span,
- "add a `self` receiver parameter to make the associated `fn` a method",
- sugg,
- Applicability::MaybeIncorrect,
- );
- "doesn't"
- } else {
- "can't"
- };
- if let Some(ident) = fn_kind.ident() {
- err.span_label(
- ident.span,
- &format!("this function {} have a `self` parameter", doesnt),
- );
- }
- }
- } else if let Some(item_kind) = self.diagnostic_metadata.current_item {
- err.span_label(
- item_kind.ident.span,
- format!(
- "`self` not allowed in {} {}",
- item_kind.kind.article(),
- item_kind.kind.descr()
- ),
- );
- }
- return (err, Vec::new());
- }
-
+ fn try_lookup_name_relaxed(
+ &mut self,
+ err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+ source: PathSource<'_>,
+ path: &[Segment],
+ span: Span,
+ res: Option<Res>,
+ base_error: &BaseError,
+ ) -> (bool, Vec<ImportSuggestion>) {
// Try to lookup name in more relaxed fashion for better error reporting.
let ident = path.last().unwrap().ident;
+ let is_expected = &|res| source.is_expected(res);
+ let ns = source.namespace();
+ let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
+ let path_str = Segment::names_to_string(path);
+ let ident_span = path.last().map_or(span, |ident| ident.ident.span);
+
let mut candidates = self
.r
.lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)
@@ -494,7 +489,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
{
// Already reported this issue on the lhs of the type ascription.
err.delay_as_bug();
- return (err, candidates);
+ return (true, candidates);
}
}
@@ -522,10 +517,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
);
}
}
+
// Try Levenshtein algorithm.
- let typo_sugg = self.lookup_typo_candidate(path, ns, is_expected);
+ let typo_sugg =
+ self.lookup_typo_candidate(path, source.namespace(), is_expected).to_opt_suggestion();
if path.len() == 1 && self.self_type_is_available() {
- if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
+ if let Some(candidate) =
+ self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
+ {
let self_is_available = self.self_value_is_available(path[0].ident.span);
match candidate {
AssocSuggestion::Field => {
@@ -540,16 +539,21 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
err.span_label(span, "a field by this name exists in `Self`");
}
}
- AssocSuggestion::MethodWithSelf if self_is_available => {
+ AssocSuggestion::MethodWithSelf { called } if self_is_available => {
+ let msg = if called {
+ "you might have meant to call the method"
+ } else {
+ "you might have meant to refer to the method"
+ };
err.span_suggestion(
span,
- "you might have meant to call the method",
+ msg,
format!("self.{path_str}"),
Applicability::MachineApplicable,
);
}
- AssocSuggestion::MethodWithSelf
- | AssocSuggestion::AssocFn
+ AssocSuggestion::MethodWithSelf { .. }
+ | AssocSuggestion::AssocFn { .. }
| AssocSuggestion::AssocConst
| AssocSuggestion::AssocType => {
err.span_suggestion(
@@ -560,8 +564,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
);
}
}
- self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);
- return (err, candidates);
+ self.r.add_typo_suggestion(err, typo_sugg, ident_span);
+ return (true, candidates);
}
// If the first argument in call is `self` suggest calling a method.
@@ -579,14 +583,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
format!("self.{path_str}({args_snippet})"),
Applicability::MachineApplicable,
);
- return (err, candidates);
+ return (true, candidates);
}
}
// Try context-dependent help if relaxed lookup didn't work.
if let Some(res) = res {
if self.smart_resolve_context_dependent_help(
- &mut err,
+ err,
span,
source,
res,
@@ -594,106 +598,148 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
&base_error.fallback_label,
) {
// We do this to avoid losing a secondary span when we override the main error span.
- self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);
- return (err, candidates);
+ self.r.add_typo_suggestion(err, typo_sugg, ident_span);
+ return (true, candidates);
}
}
+ return (false, candidates);
+ }
+ fn suggest_trait_and_bounds(
+ &mut self,
+ err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+ source: PathSource<'_>,
+ res: Option<Res>,
+ span: Span,
+ base_error: &BaseError,
+ ) -> bool {
let is_macro =
base_error.span.from_expansion() && base_error.span.desugaring_kind().is_none();
- if !self.type_ascription_suggestion(&mut err, base_error.span) {
- let mut fallback = false;
- if let (
- PathSource::Trait(AliasPossibility::Maybe),
- Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),
- false,
- ) = (source, res, is_macro)
- {
- if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
- fallback = true;
- let spans: Vec<Span> = bounds
- .iter()
- .map(|bound| bound.span())
- .filter(|&sp| sp != base_error.span)
- .collect();
+ let mut fallback = false;
- let start_span = bounds[0].span();
- // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
- let end_span = bounds.last().unwrap().span();
- // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
- let last_bound_span = spans.last().cloned().unwrap();
- let mut multi_span: MultiSpan = spans.clone().into();
- for sp in spans {
- let msg = if sp == last_bound_span {
- format!(
- "...because of {these} bound{s}",
- these = pluralize!("this", bounds.len() - 1),
- s = pluralize!(bounds.len() - 1),
- )
- } else {
- String::new()
- };
- multi_span.push_span_label(sp, msg);
- }
- multi_span
- .push_span_label(base_error.span, "expected this type to be a trait...");
- err.span_help(
- multi_span,
- "`+` is used to constrain a \"trait object\" type with lifetimes or \
- auto-traits; structs and enums can't be bound in that way",
- );
- if bounds.iter().all(|bound| match bound {
- ast::GenericBound::Outlives(_) => true,
- ast::GenericBound::Trait(tr, _) => tr.span == base_error.span,
- }) {
- let mut sugg = vec![];
- if base_error.span != start_span {
- sugg.push((start_span.until(base_error.span), String::new()));
- }
- if base_error.span != end_span {
- sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));
- }
+ if let (
+ PathSource::Trait(AliasPossibility::Maybe),
+ Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),
+ false,
+ ) = (source, res, is_macro)
+ {
+ if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
+ fallback = true;
+ let spans: Vec<Span> = bounds
+ .iter()
+ .map(|bound| bound.span())
+ .filter(|&sp| sp != base_error.span)
+ .collect();
- err.multipart_suggestion(
- "if you meant to use a type and not a trait here, remove the bounds",
- sugg,
- Applicability::MaybeIncorrect,
- );
+ let start_span = bounds[0].span();
+ // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
+ let end_span = bounds.last().unwrap().span();
+ // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
+ let last_bound_span = spans.last().cloned().unwrap();
+ let mut multi_span: MultiSpan = spans.clone().into();
+ for sp in spans {
+ let msg = if sp == last_bound_span {
+ format!(
+ "...because of {these} bound{s}",
+ these = pluralize!("this", bounds.len() - 1),
+ s = pluralize!(bounds.len() - 1),
+ )
+ } else {
+ String::new()
+ };
+ multi_span.push_span_label(sp, msg);
+ }
+ multi_span.push_span_label(base_error.span, "expected this type to be a trait...");
+ err.span_help(
+ multi_span,
+ "`+` is used to constrain a \"trait object\" type with lifetimes or \
+ auto-traits; structs and enums can't be bound in that way",
+ );
+ if bounds.iter().all(|bound| match bound {
+ ast::GenericBound::Outlives(_) => true,
+ ast::GenericBound::Trait(tr, _) => tr.span == base_error.span,
+ }) {
+ let mut sugg = vec![];
+ if base_error.span != start_span {
+ sugg.push((start_span.until(base_error.span), String::new()));
+ }
+ if base_error.span != end_span {
+ sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));
}
+
+ err.multipart_suggestion(
+ "if you meant to use a type and not a trait here, remove the bounds",
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
}
}
+ }
- fallback |= self.restrict_assoc_type_in_where_clause(span, &mut err);
+ fallback |= self.restrict_assoc_type_in_where_clause(span, err);
+ fallback
+ }
- if !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span) {
- fallback = true;
- match self.diagnostic_metadata.current_let_binding {
- Some((pat_sp, Some(ty_sp), None))
- if ty_sp.contains(base_error.span) && base_error.could_be_expr =>
- {
- err.span_suggestion_short(
- pat_sp.between(ty_sp),
- "use `=` if you meant to assign",
- " = ",
- Applicability::MaybeIncorrect,
- );
- }
- _ => {}
+ fn suggest_typo(
+ &mut self,
+ err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+ source: PathSource<'_>,
+ path: &[Segment],
+ span: Span,
+ base_error: &BaseError,
+ ) -> bool {
+ let is_expected = &|res| source.is_expected(res);
+ let ident_span = path.last().map_or(span, |ident| ident.ident.span);
+ let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
+ if let TypoCandidate::Shadowed(res) = typo_sugg
+ && let Some(id) = res.opt_def_id()
+ && let Some(sugg_span) = self.r.opt_span(id)
+ {
+ err.span_label(
+ sugg_span,
+ format!("you might have meant to refer to this {}", res.descr()),
+ );
+ return true;
+ }
+ let mut fallback = false;
+ let typo_sugg = typo_sugg.to_opt_suggestion();
+ if !self.r.add_typo_suggestion(err, typo_sugg, ident_span) {
+ fallback = true;
+ match self.diagnostic_metadata.current_let_binding {
+ Some((pat_sp, Some(ty_sp), None))
+ if ty_sp.contains(base_error.span) && base_error.could_be_expr =>
+ {
+ err.span_suggestion_short(
+ pat_sp.between(ty_sp),
+ "use `=` if you meant to assign",
+ " = ",
+ Applicability::MaybeIncorrect,
+ );
}
-
- // If the trait has a single item (which wasn't matched by Levenshtein), suggest it
- let suggestion = self.get_single_associated_item(&path, &source, is_expected);
- self.r.add_typo_suggestion(&mut err, suggestion, ident_span);
+ _ => {}
}
- if fallback {
- // Fallback label.
- err.span_label(base_error.span, base_error.fallback_label);
+
+ // If the trait has a single item (which wasn't matched by Levenshtein), suggest it
+ let suggestion = self.get_single_associated_item(&path, &source, is_expected);
+ if !self.r.add_typo_suggestion(err, suggestion, ident_span) {
+ fallback = !self.let_binding_suggestion(err, ident_span);
}
}
+ fallback
+ }
+
+ fn err_code_special_cases(
+ &mut self,
+ err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+ source: PathSource<'_>,
+ path: &[Segment],
+ span: Span,
+ ) {
if let Some(err_code) = &err.code {
if err_code == &rustc_errors::error_code!(E0425) {
for label_rib in &self.label_ribs {
for (label_ident, node_id) in &label_rib.bindings {
+ let ident = path.last().unwrap().ident;
if format!("'{}", ident) == label_ident.to_string() {
err.span_label(label_ident.span, "a label with a similar name exists");
if let PathSource::Expr(Some(Expr {
@@ -724,38 +770,116 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
}
}
}
+ }
- (err, candidates)
+ /// Emit special messages for unresolved `Self` and `self`.
+ fn suggest_self_ty(
+ &mut self,
+ err: &mut Diagnostic,
+ source: PathSource<'_>,
+ path: &[Segment],
+ span: Span,
+ ) -> bool {
+ if !is_self_type(path, source.namespace()) {
+ return false;
+ }
+ err.code(rustc_errors::error_code!(E0411));
+ err.span_label(
+ span,
+ "`Self` is only available in impls, traits, and type definitions".to_string(),
+ );
+ if let Some(item_kind) = self.diagnostic_metadata.current_item {
+ err.span_label(
+ item_kind.ident.span,
+ format!(
+ "`Self` not allowed in {} {}",
+ item_kind.kind.article(),
+ item_kind.kind.descr()
+ ),
+ );
+ }
+ true
}
- fn detect_assoct_type_constraint_meant_as_path(&self, base_span: Span, err: &mut Diagnostic) {
- let Some(ty) = self.diagnostic_metadata.current_type_path else { return; };
- let TyKind::Path(_, path) = &ty.kind else { return; };
- for segment in &path.segments {
- let Some(params) = &segment.args else { continue; };
- let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else { continue; };
- for param in &params.args {
- let ast::AngleBracketedArg::Constraint(constraint) = param else { continue; };
- let ast::AssocConstraintKind::Bound { bounds } = &constraint.kind else {
- continue;
+ fn suggest_self_value(
+ &mut self,
+ err: &mut Diagnostic,
+ source: PathSource<'_>,
+ path: &[Segment],
+ span: Span,
+ ) -> bool {
+ if !is_self_value(path, source.namespace()) {
+ return false;
+ }
+
+ debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
+ err.code(rustc_errors::error_code!(E0424));
+ err.span_label(
+ span,
+ match source {
+ PathSource::Pat => {
+ "`self` value is a keyword and may not be bound to variables or shadowed"
+ }
+ _ => "`self` value is a keyword only available in methods with a `self` parameter",
+ },
+ );
+ let is_assoc_fn = self.self_type_is_available();
+ if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function {
+ // 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()) {
+ 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 {
+ let (span, sugg) = fn_kind
+ .decl()
+ .inputs
+ .get(0)
+ .map(|p| (p.span.shrink_to_lo(), "&self, "))
+ .unwrap_or_else(|| {
+ // Try to look for the "(" after the function name, if possible.
+ // This avoids placing the suggestion into the visibility specifier.
+ let span = fn_kind
+ .ident()
+ .map_or(*span, |ident| span.with_lo(ident.span.hi()));
+ (
+ self.r
+ .session
+ .source_map()
+ .span_through_char(span, '(')
+ .shrink_to_hi(),
+ "&self",
+ )
+ });
+ err.span_suggestion_verbose(
+ span,
+ "add a `self` receiver parameter to make the associated `fn` a method",
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+ "doesn't"
+ } else {
+ "can't"
};
- for bound in bounds {
- let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)
- = bound else
- {
- continue;
- };
- if base_span == trait_ref.span {
- err.span_suggestion_verbose(
- constraint.ident.span.between(trait_ref.span),
- "you might have meant to write a path instead of an associated type bound",
- "::",
- Applicability::MachineApplicable,
- );
- }
+ if let Some(ident) = fn_kind.ident() {
+ err.span_label(
+ ident.span,
+ &format!("this function {} have a `self` parameter", doesnt),
+ );
}
}
+ } else if let Some(item_kind) = self.diagnostic_metadata.current_item {
+ err.span_label(
+ item_kind.ident.span,
+ format!(
+ "`self` not allowed in {} {}",
+ item_kind.kind.article(),
+ item_kind.kind.descr()
+ ),
+ );
}
+ true
}
fn suggest_swapping_misplaced_self_ty_and_trait(
@@ -787,6 +911,45 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
}
}
+ fn suggest_bare_struct_literal(&mut self, err: &mut Diagnostic) {
+ if let Some(span) = self.diagnostic_metadata.current_block_could_be_bare_struct_literal {
+ err.multipart_suggestion(
+ "you might have meant to write a `struct` literal",
+ vec![
+ (span.shrink_to_lo(), "{ SomeStruct ".to_string()),
+ (span.shrink_to_hi(), "}".to_string()),
+ ],
+ Applicability::HasPlaceholders,
+ );
+ }
+ }
+
+ fn suggest_pattern_match_with_let(
+ &mut self,
+ err: &mut Diagnostic,
+ source: PathSource<'_>,
+ span: Span,
+ ) {
+ if let PathSource::Expr(_) = source &&
+ let Some(Expr {
+ span: expr_span,
+ kind: ExprKind::Assign(lhs, _, _),
+ ..
+ }) = self.diagnostic_metadata.in_if_condition {
+ // Icky heuristic so we don't suggest:
+ // `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
+ // `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
+ if lhs.is_approximately_pattern() && lhs.span.contains(span) {
+ err.span_suggestion_verbose(
+ expr_span.shrink_to_lo(),
+ "you might have meant to use pattern matching",
+ "let ",
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+
fn get_single_associated_item(
&mut self,
path: &[Segment],
@@ -849,11 +1012,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else {
return false;
};
- if !(matches!(
- partial_res.base_res(),
- hir::def::Res::Def(hir::def::DefKind::AssocTy, _)
- ) && partial_res.unresolved_segments() == 0)
- {
+ if !matches!(
+ partial_res.full_res(),
+ Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _))
+ ) {
return false;
}
(ty, position, path)
@@ -867,11 +1029,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else {
return false;
};
- if !(matches!(
- partial_res.base_res(),
- hir::def::Res::Def(hir::def::DefKind::TyParam, _)
- ) && partial_res.unresolved_segments() == 0)
- {
+ if !matches!(
+ partial_res.full_res(),
+ Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _))
+ ) {
return false;
}
if let (
@@ -959,41 +1120,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
// where a brace being opened means a block is being started. Look
// ahead for the next text to see if `span` is followed by a `{`.
let sm = self.r.session.source_map();
- let mut sp = span;
- loop {
- sp = sm.next_point(sp);
- match sm.span_to_snippet(sp) {
- Ok(ref snippet) => {
- if snippet.chars().any(|c| !c.is_whitespace()) {
- break;
- }
- }
- _ => break,
- }
- }
+ let sp = sm.span_look_ahead(span, None, Some(50));
let followed_by_brace = matches!(sm.span_to_snippet(sp), Ok(ref snippet) if snippet == "{");
// In case this could be a struct literal that needs to be surrounded
// by parentheses, find the appropriate span.
- let mut i = 0;
- let mut closing_brace = None;
- loop {
- sp = sm.next_point(sp);
- match sm.span_to_snippet(sp) {
- Ok(ref snippet) => {
- if snippet == "}" {
- closing_brace = Some(span.to(sp));
- break;
- }
- }
- _ => break,
- }
- i += 1;
- // The bigger the span, the more likely we're incorrect --
- // bound it to 100 chars long.
- if i > 100 {
- break;
- }
- }
+ let closing_span = sm.span_look_ahead(span, Some("}"), Some(50));
+ let closing_brace: Option<Span> = sm
+ .span_to_snippet(closing_span)
+ .map_or(None, |s| if s == "}" { Some(span.to(closing_span)) } else { None });
(followed_by_brace, closing_brace)
}
@@ -1017,7 +1151,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
let (lhs_span, rhs_span) = match &expr.kind {
ExprKind::Field(base, ident) => (base.span, ident.span),
- ExprKind::MethodCall(_, args, span) => (args[0].span, *span),
+ ExprKind::MethodCall(_, receiver, _, span) => (receiver.span, *span),
_ => return false,
};
@@ -1330,7 +1464,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
Applicability::HasPlaceholders,
);
}
- (Res::SelfTy { .. }, _) if ns == ValueNS => {
+ (Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }, _) if ns == ValueNS => {
err.span_label(span, fallback_label);
err.note("can't use `Self` as a constructor, you must use the implemented struct");
}
@@ -1363,7 +1497,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
.filter(|(_, res)| match (kind, res) {
(AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true,
(AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true,
- (AssocItemKind::TyAlias(..), Res::Def(DefKind::AssocTy, _)) => true,
+ (AssocItemKind::Type(..), Res::Def(DefKind::AssocTy, _)) => true,
_ => false,
})
.map(|(key, _)| key.ident.name)
@@ -1377,6 +1511,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
ident: Ident,
ns: Namespace,
filter_fn: FilterFn,
+ called: bool,
) -> Option<AssocSuggestion>
where
FilterFn: Fn(Res) -> bool,
@@ -1399,20 +1534,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
{
// Look for a field with the same name in the current self_type.
if let Some(resolution) = self.r.partial_res_map.get(&node_id) {
- match resolution.base_res() {
- Res::Def(DefKind::Struct | DefKind::Union, did)
- if resolution.unresolved_segments() == 0 =>
- {
- if let Some(field_names) = self.r.field_names.get(&did) {
- if field_names
- .iter()
- .any(|&field_name| ident.name == field_name.node)
- {
- return Some(AssocSuggestion::Field);
- }
+ if let Some(Res::Def(DefKind::Struct | DefKind::Union, did)) =
+ resolution.full_res()
+ {
+ if let Some(field_names) = self.r.field_names.get(&did) {
+ if field_names.iter().any(|&field_name| ident.name == field_name.node) {
+ return Some(AssocSuggestion::Field);
}
}
- _ => {}
}
}
}
@@ -1424,10 +1553,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
return Some(match &assoc_item.kind {
ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst,
ast::AssocItemKind::Fn(box ast::Fn { sig, .. }) if sig.decl.has_self() => {
- AssocSuggestion::MethodWithSelf
+ AssocSuggestion::MethodWithSelf { called }
}
- ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn,
- ast::AssocItemKind::TyAlias(..) => AssocSuggestion::AssocType,
+ ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn { called },
+ ast::AssocItemKind::Type(..) => AssocSuggestion::AssocType,
ast::AssocItemKind::MacCall(_) => continue,
});
}
@@ -1445,10 +1574,12 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
let res = binding.res();
if filter_fn(res) {
if self.r.has_self.contains(&res.def_id()) {
- return Some(AssocSuggestion::MethodWithSelf);
+ return Some(AssocSuggestion::MethodWithSelf { called });
} else {
match res {
- Res::Def(DefKind::AssocFn, _) => return Some(AssocSuggestion::AssocFn),
+ Res::Def(DefKind::AssocFn, _) => {
+ return Some(AssocSuggestion::AssocFn { called });
+ }
Res::Def(DefKind::AssocConst, _) => {
return Some(AssocSuggestion::AssocConst);
}
@@ -1470,22 +1601,38 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
path: &[Segment],
ns: Namespace,
filter_fn: &impl Fn(Res) -> bool,
- ) -> Option<TypoSuggestion> {
+ ) -> TypoCandidate {
let mut names = Vec::new();
if path.len() == 1 {
+ let mut ctxt = path.last().unwrap().ident.span.ctxt();
+
// Search in lexical scope.
// Walk backwards up the ribs in scope and collect candidates.
for rib in self.ribs[ns].iter().rev() {
+ let rib_ctxt = if rib.kind.contains_params() {
+ ctxt.normalize_to_macros_2_0()
+ } else {
+ ctxt.normalize_to_macro_rules()
+ };
+
// Locals and type parameters
for (ident, &res) in &rib.bindings {
- if filter_fn(res) {
+ if filter_fn(res) && ident.span.ctxt() == rib_ctxt {
names.push(TypoSuggestion::typo_from_res(ident.name, res));
}
}
+
+ if let RibKind::MacroDefinition(def) = rib.kind && def == self.r.macro_def(ctxt) {
+ // If an invocation of this macro created `ident`, give up on `ident`
+ // and switch to `ident`'s source from the macro definition.
+ ctxt.remove_mark();
+ continue;
+ }
+
// Items in scope
if let RibKind::ModuleRibKind(module) = rib.kind {
// Items from this module
- self.r.add_module_candidates(module, &mut names, &filter_fn);
+ self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt));
if let ModuleKind::Block = module.kind {
// We can see through blocks
@@ -1511,7 +1658,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
}));
if let Some(prelude) = self.r.prelude {
- self.r.add_module_candidates(prelude, &mut names, &filter_fn);
+ self.r.add_module_candidates(prelude, &mut names, &filter_fn, None);
}
}
break;
@@ -1530,7 +1677,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
self.resolve_path(mod_path, Some(TypeNS), None)
{
- self.r.add_module_candidates(module, &mut names, &filter_fn);
+ self.r.add_module_candidates(module, &mut names, &filter_fn, None);
}
}
@@ -1543,10 +1690,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
name,
None,
) {
- Some(found) if found != name => {
- names.into_iter().find(|suggestion| suggestion.candidate == found)
+ Some(found) => {
+ let Some(sugg) = names.into_iter().find(|suggestion| suggestion.candidate == found) else {
+ return TypoCandidate::None;
+ };
+ if found == name {
+ TypoCandidate::Shadowed(sugg.res)
+ } else {
+ TypoCandidate::Typo(sugg)
+ }
}
- _ => None,
+ _ => TypoCandidate::None,
}
}
@@ -1616,26 +1770,16 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
}
}
if let Ok(base_snippet) = base_snippet {
- let mut sp = after_colon_sp;
- for _ in 0..100 {
- // Try to find an assignment
- sp = sm.next_point(sp);
- let snippet = sm.span_to_snippet(sp.to(sm.next_point(sp)));
- match snippet {
- Ok(ref x) if x.as_str() == "=" => {
- err.span_suggestion(
- base_span,
- "maybe you meant to write an assignment here",
- format!("let {}", base_snippet),
- Applicability::MaybeIncorrect,
- );
- show_label = false;
- break;
- }
- Ok(ref x) if x.as_str() == "\n" => break,
- Err(_) => break,
- Ok(_) => {}
- }
+ // 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;
}
}
}
@@ -1652,6 +1796,31 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
false
}
+ fn let_binding_suggestion(&self, err: &mut Diagnostic, ident_span: Span) -> bool {
+ // try to give a suggestion for this pattern: `name = 1`, which is common in other languages
+ let mut added_suggestion = false;
+ if let Some(Expr { kind: ExprKind::Assign(lhs, _rhs, _), .. }) = self.diagnostic_metadata.in_assignment &&
+ let ast::ExprKind::Path(None, _) = lhs.kind {
+ let sm = self.r.session.source_map();
+ let line_span = sm.span_extend_to_line(ident_span);
+ let ident_name = sm.span_to_snippet(ident_span).unwrap();
+ // HACK(chenyukang): make sure ident_name is at the starting of the line to protect against macros
+ if sm
+ .span_to_snippet(line_span)
+ .map_or(false, |s| s.trim().starts_with(&ident_name))
+ {
+ err.span_suggestion_verbose(
+ ident_span.shrink_to_lo(),
+ "you might have meant to introduce a new binding",
+ "let ".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ added_suggestion = true;
+ }
+ }
+ added_suggestion
+ }
+
fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
let mut result = None;
let mut seen_modules = FxHashSet::default();
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 26b9284fe..8aebb7da1 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -4,7 +4,7 @@
//! Paths in macros, imports, expressions, types, patterns are resolved here.
//! Label and lifetime names are resolved here as well.
//!
-//! Type-relative name resolution (methods, fields, associated items) happens in `rustc_typeck`.
+//! Type-relative name resolution (methods, fields, associated items) happens in `rustc_hir_analysis`.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(assert_matches)]
@@ -13,7 +13,6 @@
#![feature(if_let_guard)]
#![feature(iter_intersperse)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(never_type)]
#![recursion_limit = "256"]
#![allow(rustdoc::private_intra_doc_links)]
@@ -42,12 +41,12 @@ use rustc_hir::TraitCandidate;
use rustc_index::vec::IndexVec;
use rustc_metadata::creader::{CStore, CrateLoader};
use rustc_middle::metadata::ModChild;
-use rustc_middle::middle::privacy::AccessLevels;
+use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::span_bug;
-use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools, ResolverOutputs};
+use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools};
+use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs};
use rustc_query_system::ich::StableHashingContext;
-use rustc_session::cstore::{CrateStore, CrateStoreDyn, MetadataLoaderDyn};
+use rustc_session::cstore::{CrateStore, MetadataLoaderDyn};
use rustc_session::lint::LintBuffer;
use rustc_session::Session;
use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency};
@@ -65,15 +64,15 @@ use imports::{Import, ImportKind, ImportResolver, NameResolution};
use late::{HasGenericParams, PathSource, PatternSource};
use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
-use crate::access_levels::AccessLevelsVisitor;
+use crate::effective_visibilities::EffectiveVisibilitiesVisitor;
type Res = def::Res<NodeId>;
-mod access_levels;
mod build_reduced_graph;
mod check_unused;
mod def_collector;
mod diagnostics;
+mod effective_visibilities;
mod ident;
mod imports;
mod late;
@@ -238,6 +237,8 @@ enum ResolutionError<'a> {
trait_item_span: Span,
code: rustc_errors::DiagnosticId,
},
+ /// Error E0201: multiple impl items for the same trait item.
+ TraitImplDuplicate { name: Symbol, trait_item_span: Span, old_span: Span },
/// Inline asm `sym` operand must refer to a `fn` or `static`.
InvalidAsmSym,
}
@@ -676,6 +677,8 @@ struct UseError<'a> {
/// Path `Segment`s at the place of use that failed. Used for accurate suggestion after telling
/// the user to import the item directly.
path: Vec<Segment>,
+ /// Whether the expected source is a call
+ is_call: bool,
}
#[derive(Clone, Copy, PartialEq, Debug)]
@@ -1028,7 +1031,7 @@ pub struct Resolver<'a> {
proc_macros: Vec<NodeId>,
confused_type_with_std_module: FxHashMap<Span, Span>,
- access_levels: AccessLevels,
+ effective_visibilities: EffectiveVisibilities,
}
/// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1332,7 +1335,7 @@ impl<'a> Resolver<'a> {
trait_impls: Default::default(),
proc_macros: Default::default(),
confused_type_with_std_module: Default::default(),
- access_levels: Default::default(),
+ effective_visibilities: Default::default(),
};
let root_parent_scope = ParentScope::module(graph_root, &resolver);
@@ -1375,9 +1378,7 @@ impl<'a> Resolver<'a> {
Default::default()
}
- pub fn into_outputs(
- self,
- ) -> (Definitions, Box<CrateStoreDyn>, ResolverOutputs, ty::ResolverAstLowering) {
+ pub fn into_outputs(self) -> ResolverOutputs {
let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
let definitions = self.definitions;
let cstore = Box::new(self.crate_loader.into_cstore());
@@ -1392,13 +1393,14 @@ impl<'a> Resolver<'a> {
let glob_map = self.glob_map;
let main_def = self.main_def;
let confused_type_with_std_module = self.confused_type_with_std_module;
- let access_levels = self.access_levels;
- let resolutions = ResolverOutputs {
+ let effective_visibilities = self.effective_visibilities;
+ let global_ctxt = ResolverGlobalCtxt {
+ cstore,
source_span,
expn_that_defined,
visibilities,
has_pub_restricted,
- access_levels,
+ effective_visibilities,
extern_crate_map,
reexport_map,
glob_map,
@@ -1415,7 +1417,7 @@ impl<'a> Resolver<'a> {
confused_type_with_std_module,
registered_tools: self.registered_tools,
};
- let resolutions_lowering = ty::ResolverAstLowering {
+ let ast_lowering = ty::ResolverAstLowering {
legacy_const_generic_args: self.legacy_const_generic_args,
partial_res_map: self.partial_res_map,
import_res_map: self.import_res_map,
@@ -1428,16 +1430,15 @@ impl<'a> Resolver<'a> {
trait_map: self.trait_map,
builtin_macro_kinds: self.builtin_macro_kinds,
};
- (definitions, cstore, resolutions, resolutions_lowering)
+ ResolverOutputs { definitions, global_ctxt, ast_lowering }
}
- pub fn clone_outputs(
- &self,
- ) -> (Definitions, Box<CrateStoreDyn>, ResolverOutputs, ty::ResolverAstLowering) {
+ pub fn clone_outputs(&self) -> ResolverOutputs {
let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
let definitions = self.definitions.clone();
let cstore = Box::new(self.cstore().clone());
- let resolutions = ResolverOutputs {
+ let global_ctxt = ResolverGlobalCtxt {
+ cstore,
source_span: self.source_span.clone(),
expn_that_defined: self.expn_that_defined.clone(),
visibilities: self.visibilities.clone(),
@@ -1457,9 +1458,9 @@ impl<'a> Resolver<'a> {
proc_macros,
confused_type_with_std_module: self.confused_type_with_std_module.clone(),
registered_tools: self.registered_tools.clone(),
- access_levels: self.access_levels.clone(),
+ effective_visibilities: self.effective_visibilities.clone(),
};
- let resolutions_lowering = ty::ResolverAstLowering {
+ let ast_lowering = ty::ResolverAstLowering {
legacy_const_generic_args: self.legacy_const_generic_args.clone(),
partial_res_map: self.partial_res_map.clone(),
import_res_map: self.import_res_map.clone(),
@@ -1472,7 +1473,7 @@ impl<'a> Resolver<'a> {
trait_map: self.trait_map.clone(),
builtin_macro_kinds: self.builtin_macro_kinds.clone(),
};
- (definitions, cstore, resolutions, resolutions_lowering)
+ ResolverOutputs { definitions, global_ctxt, ast_lowering }
}
fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
@@ -1520,8 +1521,8 @@ impl<'a> Resolver<'a> {
pub fn resolve_crate(&mut self, krate: &Crate) {
self.session.time("resolve_crate", || {
self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports());
- self.session.time("resolve_access_levels", || {
- AccessLevelsVisitor::compute_access_levels(self, krate)
+ self.session.time("compute_effective_visibilities", || {
+ EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate)
});
self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
self.session.time("late_resolve_crate", || self.late_resolve_crate(krate));
@@ -1882,12 +1883,10 @@ impl<'a> Resolver<'a> {
match self.maybe_resolve_path(&segments, Some(ns), &parent_scope) {
PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()),
- PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
- Some(path_res.base_res())
+ PathResult::NonModule(path_res) => path_res.full_res(),
+ PathResult::Module(ModuleOrUniformRoot::ExternPrelude) | PathResult::Failed { .. } => {
+ None
}
- PathResult::Module(ModuleOrUniformRoot::ExternPrelude)
- | PathResult::NonModule(..)
- | PathResult::Failed { .. } => None,
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
}
}
@@ -1911,6 +1910,11 @@ impl<'a> Resolver<'a> {
}
}
+ /// For rustdoc.
+ pub fn get_partial_res(&self, node_id: NodeId) -> Option<PartialRes> {
+ self.partial_res_map.get(&node_id).copied()
+ }
+
/// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
#[inline]
pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
@@ -1938,12 +1942,8 @@ impl<'a> Resolver<'a> {
return None;
}
- let partial_res = self.partial_res_map.get(&expr.id)?;
- if partial_res.unresolved_segments() != 0 {
- return None;
- }
-
- if let Res::Def(def::DefKind::Fn, def_id) = partial_res.base_res() {
+ let res = self.partial_res_map.get(&expr.id)?.full_res()?;
+ if let Res::Def(def::DefKind::Fn, def_id) = res {
// We only support cross-crate argument rewriting. Uses
// within the same crate should be updated to use the new
// const generics style.
@@ -2065,7 +2065,7 @@ struct Finalize {
/// Span of the whole path or some its characteristic fragment.
/// E.g. span of `b` in `foo::{a, b, c}`, or full span for regular paths.
path_span: Span,
- /// Span of the path start, suitable for prepending something to to it.
+ /// Span of the path start, suitable for prepending something to it.
/// E.g. span of `foo` in `foo::{a, b, c}`, or full span for regular paths.
root_span: Span,
/// Whether to report privacy errors or silently return "no resolution" for them,
@@ -2082,7 +2082,3 @@ impl Finalize {
Finalize { node_id, path_span, root_span, report_private: true }
}
}
-
-pub fn provide(providers: &mut Providers) {
- late::lifetimes::provide(providers);
-}
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index dafa10e9e..9526296f9 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -12,7 +12,7 @@ use rustc_attr::StabilityLevel;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, Applicability};
use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, ResolverExpand};
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
use rustc_expand::compile_declarative_macro;
@@ -590,9 +590,7 @@ impl<'a> Resolver<'a> {
let res = if path.len() > 1 {
let res = match self.maybe_resolve_path(&path, Some(MacroNS), parent_scope) {
- PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
- Ok(path_res.base_res())
- }
+ PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res),
PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
PathResult::NonModule(..)
| PathResult::Indeterminate
@@ -692,12 +690,23 @@ impl<'a> Resolver<'a> {
Some(Finalize::new(ast::CRATE_NODE_ID, path_span)),
None,
) {
- PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
- let res = path_res.base_res();
- check_consistency(self, &path, path_span, kind, initial_res, res);
+ PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => {
+ check_consistency(self, &path, path_span, kind, initial_res, res)
}
path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => {
+ let mut suggestion = None;
let (span, label) = if let PathResult::Failed { span, label, .. } = path_res {
+ // try to suggest if it's not a macro, maybe a function
+ if let PathResult::NonModule(partial_res) = self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope)
+ && partial_res.unresolved_segments() == 0 {
+ let sm = self.session.source_map();
+ let exclamation_span = sm.next_point(span);
+ suggestion = Some((
+ vec![(exclamation_span, "".to_string())],
+ format!("{} is not a macro, but a {}, try to remove `!`", Segment::names_to_string(&path), partial_res.base_res().descr()),
+ Applicability::MaybeIncorrect
+ ));
+ }
(span, label)
} else {
(
@@ -711,7 +720,7 @@ impl<'a> Resolver<'a> {
};
self.report_error(
span,
- ResolutionError::FailedToResolve { label, suggestion: None },
+ ResolutionError::FailedToResolve { label, suggestion },
);
}
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index 8bd42d8d2..df5d992f6 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -57,7 +57,7 @@ macro_rules! access_from {
($save_ctxt:expr, $id:expr) => {
Access {
public: $save_ctxt.tcx.visibility($id).is_public(),
- reachable: $save_ctxt.access_levels.is_reachable($id),
+ reachable: $save_ctxt.effective_visibilities.is_reachable($id),
}
};
}
@@ -345,14 +345,14 @@ impl<'tcx> DumpVisitor<'tcx> {
body: hir::BodyId,
) {
let map = self.tcx.hir();
- self.nest_typeck_results(item.def_id, |v| {
+ self.nest_typeck_results(item.owner_id.def_id, |v| {
let body = map.body(body);
if let Some(fn_data) = v.save_ctxt.get_item_data(item) {
down_cast_data!(fn_data, DefData, item.span);
v.process_formals(body.params, &fn_data.qualname);
v.process_generic_params(ty_params, &fn_data.qualname, item.hir_id());
- v.dumper.dump_def(&access_from!(v.save_ctxt, item.def_id), fn_data);
+ v.dumper.dump_def(&access_from!(v.save_ctxt, item.owner_id.def_id), fn_data);
}
for arg in decl.inputs {
@@ -373,10 +373,10 @@ impl<'tcx> DumpVisitor<'tcx> {
typ: &'tcx hir::Ty<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
) {
- self.nest_typeck_results(item.def_id, |v| {
+ self.nest_typeck_results(item.owner_id.def_id, |v| {
if let Some(var_data) = v.save_ctxt.get_item_data(item) {
down_cast_data!(var_data, DefData, item.span);
- v.dumper.dump_def(&access_from!(v.save_ctxt, item.def_id), var_data);
+ v.dumper.dump_def(&access_from!(v.save_ctxt, item.owner_id.def_id), var_data);
}
v.visit_ty(&typ);
v.visit_expr(expr);
@@ -436,7 +436,7 @@ impl<'tcx> DumpVisitor<'tcx> {
) {
debug!("process_struct {:?} {:?}", item, item.span);
let name = item.ident.to_string();
- let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id()));
+ let qualname = format!("::{}", self.tcx.def_path_str(item.owner_id.to_def_id()));
let kind = match item.kind {
hir::ItemKind::Struct(_, _) => DefKind::Struct,
@@ -473,10 +473,10 @@ impl<'tcx> DumpVisitor<'tcx> {
let span = self.span_from_span(item.ident.span);
let attrs = self.tcx.hir().attrs(item.hir_id());
self.dumper.dump_def(
- &access_from!(self.save_ctxt, item.def_id),
+ &access_from!(self.save_ctxt, item.owner_id.def_id),
Def {
kind,
- id: id_from_def_id(item.def_id.to_def_id()),
+ id: id_from_def_id(item.owner_id.to_def_id()),
span,
name,
qualname: qualname.clone(),
@@ -491,7 +491,7 @@ impl<'tcx> DumpVisitor<'tcx> {
);
}
- self.nest_typeck_results(item.def_id, |v| {
+ self.nest_typeck_results(item.owner_id.def_id, |v| {
for field in def.fields() {
v.process_struct_field_def(field, item.hir_id());
v.visit_ty(&field.ty);
@@ -513,7 +513,7 @@ impl<'tcx> DumpVisitor<'tcx> {
};
down_cast_data!(enum_data, DefData, item.span);
- let access = access_from!(self.save_ctxt, item.def_id);
+ let access = access_from!(self.save_ctxt, item.owner_id.def_id);
for variant in enum_definition.variants {
let name = variant.ident.name.to_string();
@@ -528,7 +528,7 @@ impl<'tcx> DumpVisitor<'tcx> {
if !self.span.filter_generated(name_span) {
let span = self.span_from_span(name_span);
let id = id_from_hir_id(variant.id, &self.save_ctxt);
- let parent = Some(id_from_def_id(item.def_id.to_def_id()));
+ let parent = Some(id_from_def_id(item.owner_id.to_def_id()));
let attrs = self.tcx.hir().attrs(variant.id);
self.dumper.dump_def(
@@ -566,7 +566,7 @@ impl<'tcx> DumpVisitor<'tcx> {
if !self.span.filter_generated(name_span) {
let span = self.span_from_span(name_span);
let id = id_from_hir_id(variant.id, &self.save_ctxt);
- let parent = Some(id_from_def_id(item.def_id.to_def_id()));
+ let parent = Some(id_from_def_id(item.owner_id.to_def_id()));
let attrs = self.tcx.hir().attrs(variant.id);
self.dumper.dump_def(
@@ -612,14 +612,14 @@ impl<'tcx> DumpVisitor<'tcx> {
}
let map = self.tcx.hir();
- self.nest_typeck_results(item.def_id, |v| {
+ self.nest_typeck_results(item.owner_id.def_id, |v| {
v.visit_ty(&impl_.self_ty);
if let Some(trait_ref) = &impl_.of_trait {
v.process_path(trait_ref.hir_ref_id, &hir::QPath::Resolved(None, &trait_ref.path));
}
v.process_generic_params(&impl_.generics, "", item.hir_id());
for impl_item in impl_.items {
- v.process_impl_item(map.impl_item(impl_item.id), item.def_id.to_def_id());
+ v.process_impl_item(map.impl_item(impl_item.id), item.owner_id.to_def_id());
}
});
}
@@ -632,7 +632,7 @@ impl<'tcx> DumpVisitor<'tcx> {
methods: &'tcx [hir::TraitItemRef],
) {
let name = item.ident.to_string();
- let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id()));
+ let qualname = format!("::{}", self.tcx.def_path_str(item.owner_id.to_def_id()));
let mut val = name.clone();
if !generics.params.is_empty() {
val.push_str(&generic_params_to_string(generics.params));
@@ -642,13 +642,13 @@ impl<'tcx> DumpVisitor<'tcx> {
val.push_str(&bounds_to_string(trait_refs));
}
if !self.span.filter_generated(item.ident.span) {
- let id = id_from_def_id(item.def_id.to_def_id());
+ let id = id_from_def_id(item.owner_id.to_def_id());
let span = self.span_from_span(item.ident.span);
let children =
- methods.iter().map(|i| id_from_def_id(i.id.def_id.to_def_id())).collect();
+ methods.iter().map(|i| id_from_def_id(i.id.owner_id.to_def_id())).collect();
let attrs = self.tcx.hir().attrs(item.hir_id());
self.dumper.dump_def(
- &access_from!(self.save_ctxt, item.def_id),
+ &access_from!(self.save_ctxt, item.owner_id.def_id),
Def {
kind: DefKind::Trait,
id,
@@ -692,7 +692,7 @@ impl<'tcx> DumpVisitor<'tcx> {
kind: RelationKind::SuperTrait,
span,
from: id_from_def_id(id),
- to: id_from_def_id(item.def_id.to_def_id()),
+ to: id_from_def_id(item.owner_id.to_def_id()),
});
}
}
@@ -702,7 +702,7 @@ impl<'tcx> DumpVisitor<'tcx> {
self.process_generic_params(generics, &qualname, item.hir_id());
for method in methods {
let map = self.tcx.hir();
- self.process_trait_item(map.trait_item(method.id), item.def_id.to_def_id())
+ self.process_trait_item(map.trait_item(method.id), item.owner_id.to_def_id())
}
}
@@ -710,7 +710,7 @@ impl<'tcx> DumpVisitor<'tcx> {
fn process_mod(&mut self, item: &'tcx hir::Item<'tcx>) {
if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
down_cast_data!(mod_data, DefData, item.span);
- self.dumper.dump_def(&access_from!(self.save_ctxt, item.def_id), mod_data);
+ self.dumper.dump_def(&access_from!(self.save_ctxt, item.owner_id.def_id), mod_data);
}
}
@@ -913,7 +913,8 @@ impl<'tcx> DumpVisitor<'tcx> {
| HirDefKind::AssocTy,
_,
)
- | Res::SelfTy { .. } => {
+ | Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. } => {
self.dump_path_segment_ref(
id,
&hir::PathSegment::new(ident, hir::HirId::INVALID, Res::Err),
@@ -980,7 +981,7 @@ impl<'tcx> DumpVisitor<'tcx> {
let body = body.map(|b| self.tcx.hir().body(b).value);
let attrs = self.tcx.hir().attrs(trait_item.hir_id());
self.process_assoc_const(
- trait_item.def_id,
+ trait_item.owner_id.def_id,
trait_item.ident,
&ty,
body,
@@ -994,7 +995,7 @@ impl<'tcx> DumpVisitor<'tcx> {
self.process_method(
sig,
body,
- trait_item.def_id,
+ trait_item.owner_id.def_id,
trait_item.ident,
&trait_item.generics,
trait_item.span,
@@ -1004,11 +1005,11 @@ impl<'tcx> DumpVisitor<'tcx> {
// FIXME do something with _bounds (for type refs)
let name = trait_item.ident.name.to_string();
let qualname =
- format!("::{}", self.tcx.def_path_str(trait_item.def_id.to_def_id()));
+ format!("::{}", self.tcx.def_path_str(trait_item.owner_id.to_def_id()));
if !self.span.filter_generated(trait_item.ident.span) {
let span = self.span_from_span(trait_item.ident.span);
- let id = id_from_def_id(trait_item.def_id.to_def_id());
+ let id = id_from_def_id(trait_item.owner_id.to_def_id());
let attrs = self.tcx.hir().attrs(trait_item.hir_id());
self.dumper.dump_def(
@@ -1050,7 +1051,7 @@ impl<'tcx> DumpVisitor<'tcx> {
let body = self.tcx.hir().body(body);
let attrs = self.tcx.hir().attrs(impl_item.hir_id());
self.process_assoc_const(
- impl_item.def_id,
+ impl_item.owner_id.def_id,
impl_item.ident,
&ty,
Some(&body.value),
@@ -1062,13 +1063,13 @@ impl<'tcx> DumpVisitor<'tcx> {
self.process_method(
sig,
Some(body),
- impl_item.def_id,
+ impl_item.owner_id.def_id,
impl_item.ident,
&impl_item.generics,
impl_item.span,
);
}
- hir::ImplItemKind::TyAlias(ref ty) => {
+ hir::ImplItemKind::Type(ref ty) => {
// FIXME: uses of the assoc type should ideally point to this
// 'def' and the name here should be a ref to the def in the
// trait.
@@ -1087,7 +1088,7 @@ impl<'tcx> DumpVisitor<'tcx> {
let filename = sm.span_to_filename(krate_mod.spans.inner_span);
let data_id = id_from_hir_id(id, &self.save_ctxt);
let children =
- krate_mod.item_ids.iter().map(|i| id_from_def_id(i.def_id.to_def_id())).collect();
+ krate_mod.item_ids.iter().map(|i| id_from_def_id(i.owner_id.to_def_id())).collect();
let span = self.span_from_span(krate_mod.spans.inner_span);
let attrs = self.tcx.hir().attrs(id);
@@ -1136,10 +1137,10 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
hir::ItemKind::Use(path, hir::UseKind::Single) => {
let sub_span = path.segments.last().unwrap().ident.span;
if !self.span.filter_generated(sub_span) {
- let access = access_from!(self.save_ctxt, item.def_id);
+ let access = access_from!(self.save_ctxt, item.owner_id.def_id);
let ref_id = self.lookup_def_id(item.hir_id()).map(id_from_def_id);
let span = self.span_from_span(sub_span);
- let parent = self.save_ctxt.tcx.local_parent(item.def_id);
+ let parent = self.save_ctxt.tcx.local_parent(item.owner_id.def_id);
self.dumper.import(
&access,
Import {
@@ -1157,16 +1158,16 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
}
hir::ItemKind::Use(path, hir::UseKind::Glob) => {
// Make a comma-separated list of names of imported modules.
- let names = self.tcx.names_imported_by_glob_use(item.def_id);
+ let names = self.tcx.names_imported_by_glob_use(item.owner_id.def_id);
let names: Vec<_> = names.iter().map(|n| n.to_string()).collect();
// Otherwise it's a span with wrong macro expansion info, which
// we don't want to track anyway, since it's probably macro-internal `use`
if let Some(sub_span) = self.span.sub_span_of_star(item.span) {
if !self.span.filter_generated(item.span) {
- let access = access_from!(self.save_ctxt, item.def_id);
+ let access = access_from!(self.save_ctxt, item.owner_id.def_id);
let span = self.span_from_span(sub_span);
- let parent = self.save_ctxt.tcx.local_parent(item.def_id);
+ let parent = self.save_ctxt.tcx.local_parent(item.owner_id.def_id);
self.dumper.import(
&access,
Import {
@@ -1187,7 +1188,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
let name_span = item.ident.span;
if !self.span.filter_generated(name_span) {
let span = self.span_from_span(name_span);
- let parent = self.save_ctxt.tcx.local_parent(item.def_id);
+ let parent = self.save_ctxt.tcx.local_parent(item.owner_id.def_id);
self.dumper.import(
&Access { public: false, reachable: false },
Import {
@@ -1227,15 +1228,15 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
intravisit::walk_mod(self, m, item.hir_id());
}
hir::ItemKind::TyAlias(ty, ref generics) => {
- let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id()));
+ let qualname = format!("::{}", self.tcx.def_path_str(item.owner_id.to_def_id()));
let value = ty_to_string(&ty);
if !self.span.filter_generated(item.ident.span) {
let span = self.span_from_span(item.ident.span);
- let id = id_from_def_id(item.def_id.to_def_id());
+ let id = id_from_def_id(item.owner_id.to_def_id());
let attrs = self.tcx.hir().attrs(item.hir_id());
self.dumper.dump_def(
- &access_from!(self.save_ctxt, item.def_id),
+ &access_from!(self.save_ctxt, item.owner_id.def_id),
Def {
kind: DefKind::Type,
id,
@@ -1323,7 +1324,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
}
hir::TyKind::OpaqueDef(item_id, _, _) => {
let item = self.tcx.hir().item(item_id);
- self.nest_typeck_results(item_id.def_id, |v| v.visit_item(item));
+ self.nest_typeck_results(item_id.owner_id.def_id, |v| v.visit_item(item));
}
_ => intravisit::walk_ty(self, t),
}
@@ -1430,7 +1431,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
}
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
- let access = access_from!(self.save_ctxt, item.def_id);
+ let access = access_from!(self.save_ctxt, item.owner_id.def_id);
match item.kind {
hir::ForeignItemKind::Fn(decl, _, ref generics) => {
diff --git a/compiler/rustc_save_analysis/src/errors.rs b/compiler/rustc_save_analysis/src/errors.rs
index f0ce41d02..585aac8c1 100644
--- a/compiler/rustc_save_analysis/src/errors.rs
+++ b/compiler/rustc_save_analysis/src/errors.rs
@@ -1,9 +1,9 @@
-use rustc_macros::SessionDiagnostic;
+use rustc_macros::Diagnostic;
use std::path::Path;
-#[derive(SessionDiagnostic)]
-#[diag(save_analysis::could_not_open)]
+#[derive(Diagnostic)]
+#[diag(save_analysis_could_not_open)]
pub(crate) struct CouldNotOpen<'a> {
pub file_name: &'a Path,
pub err: std::io::Error,
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index ce03c2a8a..d0155c908 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -1,6 +1,5 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(if_let_guard)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
#![feature(never_type)]
@@ -27,7 +26,7 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::Node;
use rustc_hir_pretty::{enum_def_to_string, fn_to_string, ty_to_string};
use rustc_middle::hir::nested_filter;
-use rustc_middle::middle::privacy::AccessLevels;
+use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::ty::{self, print::with_no_trimmed_paths, DefIdTree, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_session::config::{CrateType, Input, OutputType};
@@ -55,7 +54,7 @@ use rls_data::{
pub struct SaveContext<'tcx> {
tcx: TyCtxt<'tcx>,
maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
- access_levels: &'tcx AccessLevels,
+ effective_visibilities: &'tcx EffectiveVisibilities,
span_utils: SpanUtils<'tcx>,
config: Config,
impl_counter: Cell<u32>,
@@ -142,7 +141,7 @@ impl<'tcx> SaveContext<'tcx> {
}
pub fn get_extern_item_data(&self, item: &hir::ForeignItem<'_>) -> Option<Data> {
- let def_id = item.def_id.to_def_id();
+ let def_id = item.owner_id.to_def_id();
let qualname = format!("::{}", self.tcx.def_path_str(def_id));
let attrs = self.tcx.hir().attrs(item.hir_id());
match item.kind {
@@ -206,7 +205,7 @@ impl<'tcx> SaveContext<'tcx> {
}
pub fn get_item_data(&self, item: &hir::Item<'_>) -> Option<Data> {
- let def_id = item.def_id.to_def_id();
+ let def_id = item.owner_id.to_def_id();
let attrs = self.tcx.hir().attrs(item.hir_id());
match item.kind {
hir::ItemKind::Fn(ref sig, ref generics, _) => {
@@ -298,7 +297,7 @@ impl<'tcx> SaveContext<'tcx> {
children: m
.item_ids
.iter()
- .map(|i| id_from_def_id(i.def_id.to_def_id()))
+ .map(|i| id_from_def_id(i.owner_id.to_def_id()))
.collect(),
decl_id: None,
docs: self.docs_for_attrs(attrs),
@@ -364,7 +363,7 @@ impl<'tcx> SaveContext<'tcx> {
parent: None,
children: items
.iter()
- .map(|i| id_from_def_id(i.id.def_id.to_def_id()))
+ .map(|i| id_from_def_id(i.id.owner_id.to_def_id()))
.collect(),
docs: String::new(),
sig: None,
@@ -622,7 +621,7 @@ impl<'tcx> SaveContext<'tcx> {
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => {
// #75962: `self.typeck_results` may be different from the `hir_id`'s result.
if self.tcx.has_typeck_results(hir_id.owner.to_def_id()) {
- self.tcx.typeck(hir_id.owner).qpath_res(qpath, hir_id)
+ self.tcx.typeck(hir_id.owner.def_id).qpath_res(qpath, hir_id)
} else {
Res::Err
}
@@ -741,7 +740,8 @@ impl<'tcx> SaveContext<'tcx> {
_,
)
| Res::PrimTy(..)
- | Res::SelfTy { .. }
+ | Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. }
| Res::ToolMod
| Res::NonMacroAttr(..)
| Res::SelfCtor(..)
@@ -806,7 +806,7 @@ impl<'tcx> SaveContext<'tcx> {
fn lookup_def_id(&self, ref_id: hir::HirId) -> Option<DefId> {
match self.get_path_res(ref_id) {
- Res::PrimTy(_) | Res::SelfTy { .. } | Res::Err => None,
+ Res::PrimTy(_) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Err => None,
def => def.opt_def_id(),
}
}
@@ -968,16 +968,16 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>(
info!("Dumping crate {}", cratename);
// Privacy checking must be done outside of type inference; use a
- // fallback in case the access levels couldn't have been correctly computed.
- let access_levels = match tcx.sess.compile_status() {
- Ok(..) => tcx.privacy_access_levels(()),
- Err(..) => tcx.arena.alloc(AccessLevels::default()),
+ // fallback in case effective visibilities couldn't have been correctly computed.
+ let effective_visibilities = match tcx.sess.compile_status() {
+ Ok(..) => tcx.effective_visibilities(()),
+ Err(..) => tcx.arena.alloc(EffectiveVisibilities::default()),
};
let save_ctxt = SaveContext {
tcx,
maybe_typeck_results: None,
- access_levels: &access_levels,
+ effective_visibilities: &effective_visibilities,
span_utils: SpanUtils::new(&tcx.sess),
config: find_config(config),
impl_counter: Cell::new(0),
@@ -1041,7 +1041,7 @@ fn id_from_hir_id(id: hir::HirId, scx: &SaveContext<'_>) -> rls_data::Id {
// crate (very unlikely to actually happen).
rls_data::Id {
krate: LOCAL_CRATE.as_u32(),
- index: id.owner.local_def_index.as_u32() | id.local_id.as_u32().reverse_bits(),
+ index: id.owner.def_id.local_def_index.as_u32() | id.local_id.as_u32().reverse_bits(),
}
})
}
diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs
index bae1828cd..83c51d213 100644
--- a/compiler/rustc_save_analysis/src/sig.rs
+++ b/compiler/rustc_save_analysis/src/sig.rs
@@ -337,7 +337,7 @@ impl<'hir> Sig for hir::Item<'hir> {
}
let name = self.ident.to_string();
let defs = vec![SigElement {
- id: id_from_def_id(self.def_id.to_def_id()),
+ id: id_from_def_id(self.owner_id.to_def_id()),
start: offset + text.len(),
end: offset + text.len() + name.len(),
}];
@@ -359,7 +359,7 @@ impl<'hir> Sig for hir::Item<'hir> {
let mut text = "const ".to_owned();
let name = self.ident.to_string();
let defs = vec![SigElement {
- id: id_from_def_id(self.def_id.to_def_id()),
+ id: id_from_def_id(self.owner_id.to_def_id()),
start: offset + text.len(),
end: offset + text.len() + name.len(),
}];
@@ -428,7 +428,7 @@ impl<'hir> Sig for hir::Item<'hir> {
let mut text = "mod ".to_owned();
let name = self.ident.to_string();
let defs = vec![SigElement {
- id: id_from_def_id(self.def_id.to_def_id()),
+ id: id_from_def_id(self.owner_id.to_def_id()),
start: offset + text.len(),
end: offset + text.len() + name.len(),
}];
@@ -579,7 +579,7 @@ impl<'hir> Sig for hir::Path<'hir> {
let res = scx.get_path_res(id.ok_or("Missing id for Path")?);
let (name, start, end) = match res {
- Res::PrimTy(..) | Res::SelfTy { .. } | Res::Err => {
+ Res::PrimTy(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Err => {
return Ok(Signature { text: path_to_string(self), defs: vec![], refs: vec![] });
}
Res::Def(DefKind::AssocConst | DefKind::Variant | DefKind::Ctor(..), _) => {
@@ -764,7 +764,7 @@ impl<'hir> Sig for hir::ForeignItem<'hir> {
}
let name = self.ident.to_string();
let defs = vec![SigElement {
- id: id_from_def_id(self.def_id.to_def_id()),
+ id: id_from_def_id(self.owner_id.to_def_id()),
start: offset + text.len(),
end: offset + text.len() + name.len(),
}];
@@ -780,7 +780,7 @@ impl<'hir> Sig for hir::ForeignItem<'hir> {
let mut text = "type ".to_owned();
let name = self.ident.to_string();
let defs = vec![SigElement {
- id: id_from_def_id(self.def_id.to_def_id()),
+ id: id_from_def_id(self.owner_id.to_def_id()),
start: offset + text.len(),
end: offset + text.len() + name.len(),
}];
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index fa9c7bd54..1f8d2336c 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -14,7 +14,6 @@ Core encoding and decoding interfaces.
#![feature(min_specialization)]
#![feature(core_intrinsics)]
#![feature(maybe_uninit_slice)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(new_uninit)]
#![feature(allocator_api)]
#![cfg_attr(test, feature(test))]
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index 5c17ef6ac..f35cc08f4 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -193,7 +193,9 @@ impl FileEncoder {
// shaves an instruction off those code paths (on x86 at least).
assert!(capacity <= usize::MAX - max_leb128_len());
- let file = File::create(path)?;
+ // 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),
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 8bb3878fb..f2ee52262 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -537,6 +537,7 @@ pub enum PrintRequest {
TargetLibdir,
CrateName,
Cfg,
+ CallingConventions,
TargetList,
TargetCPUs,
TargetFeatures,
@@ -1353,8 +1354,8 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
"",
"print",
"Compiler information to print on stdout",
- "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
- target-cpus|target-features|relocation-models|code-models|\
+ "[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|native-static-libs|stack-protector-strategies|\
link-args]",
),
@@ -1793,6 +1794,7 @@ fn collect_print_requests(
"sysroot" => PrintRequest::Sysroot,
"target-libdir" => PrintRequest::TargetLibdir,
"cfg" => PrintRequest::Cfg,
+ "calling-conventions" => PrintRequest::CallingConventions,
"target-list" => PrintRequest::TargetList,
"target-cpus" => PrintRequest::TargetCPUs,
"target-features" => PrintRequest::TargetFeatures,
diff --git a/compiler/rustc_session/src/config/sigpipe.rs b/compiler/rustc_session/src/config/sigpipe.rs
index a5c94118a..53692ad7c 100644
--- a/compiler/rustc_session/src/config/sigpipe.rs
+++ b/compiler/rustc_session/src/config/sigpipe.rs
@@ -1,5 +1,13 @@
//! NOTE: Keep these constants in sync with `library/std/src/sys/unix/mod.rs`!
+/// The default value if `#[unix_sigpipe]` is not specified. This resolves
+/// to `SIG_IGN` in `library/std/src/sys/unix/mod.rs`.
+///
+/// Note that `SIG_IGN` has been the Rust default since 2014. See
+/// <https://github.com/rust-lang/rust/issues/62569>.
+#[allow(dead_code)]
+pub const DEFAULT: u8 = 0;
+
/// Do not touch `SIGPIPE`. Use whatever the parent process uses.
#[allow(dead_code)]
pub const INHERIT: u8 = 1;
@@ -15,8 +23,3 @@ pub const SIG_IGN: u8 = 2;
/// such as `head -n 1`.
#[allow(dead_code)]
pub const SIG_DFL: u8 = 3;
-
-/// `SIG_IGN` has been the Rust default since 2014. See
-/// <https://github.com/rust-lang/rust/issues/62569>.
-#[allow(dead_code)]
-pub const DEFAULT: u8 = SIG_IGN;
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index c6596ff24..bf542faec 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -1,15 +1,13 @@
use std::num::NonZeroU32;
use crate::cgu_reuse_tracker::CguReuse;
-use crate::{self as rustc_session, SessionDiagnostic};
-use rustc_errors::{fluent, DiagnosticBuilder, ErrorGuaranteed, Handler, MultiSpan};
-use rustc_macros::SessionDiagnostic;
+use rustc_errors::MultiSpan;
+use rustc_macros::Diagnostic;
use rustc_span::{Span, Symbol};
-use rustc_target::abi::TargetDataLayoutErrors;
use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
-#[derive(SessionDiagnostic)]
-#[diag(session::incorrect_cgu_reuse_type)]
+#[derive(Diagnostic)]
+#[diag(session_incorrect_cgu_reuse_type)]
pub struct IncorrectCguReuseType<'a> {
#[primary_span]
pub span: Span,
@@ -19,166 +17,115 @@ pub struct IncorrectCguReuseType<'a> {
pub at_least: u8,
}
-#[derive(SessionDiagnostic)]
-#[diag(session::cgu_not_recorded)]
+#[derive(Diagnostic)]
+#[diag(session_cgu_not_recorded)]
pub struct CguNotRecorded<'a> {
pub cgu_user_name: &'a str,
pub cgu_name: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(session::feature_gate_error, code = "E0658")]
+#[derive(Diagnostic)]
+#[diag(session_feature_gate_error, code = "E0658")]
pub struct FeatureGateError<'a> {
#[primary_span]
pub span: MultiSpan,
pub explain: &'a str,
}
-#[derive(SessionSubdiagnostic)]
-#[note(session::feature_diagnostic_for_issue)]
+#[derive(Subdiagnostic)]
+#[note(session_feature_diagnostic_for_issue)]
pub struct FeatureDiagnosticForIssue {
pub n: NonZeroU32,
}
-#[derive(SessionSubdiagnostic)]
-#[help(session::feature_diagnostic_help)]
+#[derive(Subdiagnostic)]
+#[help(session_feature_diagnostic_help)]
pub struct FeatureDiagnosticHelp {
pub feature: Symbol,
}
-impl SessionDiagnostic<'_, !> for TargetDataLayoutErrors<'_> {
- fn into_diagnostic(self, sess: &Handler) -> DiagnosticBuilder<'_, !> {
- let mut diag;
- match self {
- TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => {
- diag = sess.struct_fatal(fluent::session::target_invalid_address_space);
- diag.set_arg("addr_space", addr_space);
- diag.set_arg("cause", cause);
- diag.set_arg("err", err);
- diag
- }
- TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => {
- diag = sess.struct_fatal(fluent::session::target_invalid_bits);
- diag.set_arg("kind", kind);
- diag.set_arg("bit", bit);
- diag.set_arg("cause", cause);
- diag.set_arg("err", err);
- diag
- }
- TargetDataLayoutErrors::MissingAlignment { cause } => {
- diag = sess.struct_fatal(fluent::session::target_missing_alignment);
- diag.set_arg("cause", cause);
- diag
- }
- TargetDataLayoutErrors::InvalidAlignment { cause, err } => {
- diag = sess.struct_fatal(fluent::session::target_invalid_alignment);
- diag.set_arg("cause", cause);
- diag.set_arg("err", err);
- diag
- }
- TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => {
- diag = sess.struct_fatal(fluent::session::target_inconsistent_architecture);
- diag.set_arg("dl", dl);
- diag.set_arg("target", target);
- diag
- }
- TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => {
- diag = sess.struct_fatal(fluent::session::target_inconsistent_pointer_width);
- diag.set_arg("pointer_size", pointer_size);
- diag.set_arg("target", target);
- diag
- }
- TargetDataLayoutErrors::InvalidBitsSize { err } => {
- diag = sess.struct_fatal(fluent::session::target_invalid_bits_size);
- diag.set_arg("err", err);
- diag
- }
- }
- }
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(session::not_circumvent_feature)]
+#[derive(Diagnostic)]
+#[diag(session_not_circumvent_feature)]
pub struct NotCircumventFeature;
-#[derive(SessionDiagnostic)]
-#[diag(session::linker_plugin_lto_windows_not_supported)]
+#[derive(Diagnostic)]
+#[diag(session_linker_plugin_lto_windows_not_supported)]
pub struct LinkerPluginToWindowsNotSupported;
-#[derive(SessionDiagnostic)]
-#[diag(session::profile_use_file_does_not_exist)]
+#[derive(Diagnostic)]
+#[diag(session_profile_use_file_does_not_exist)]
pub struct ProfileUseFileDoesNotExist<'a> {
pub path: &'a std::path::Path,
}
-#[derive(SessionDiagnostic)]
-#[diag(session::profile_sample_use_file_does_not_exist)]
+#[derive(Diagnostic)]
+#[diag(session_profile_sample_use_file_does_not_exist)]
pub struct ProfileSampleUseFileDoesNotExist<'a> {
pub path: &'a std::path::Path,
}
-#[derive(SessionDiagnostic)]
-#[diag(session::target_requires_unwind_tables)]
+#[derive(Diagnostic)]
+#[diag(session_target_requires_unwind_tables)]
pub struct TargetRequiresUnwindTables;
-#[derive(SessionDiagnostic)]
-#[diag(session::sanitizer_not_supported)]
+#[derive(Diagnostic)]
+#[diag(session_sanitizer_not_supported)]
pub struct SanitizerNotSupported {
pub us: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(session::sanitizers_not_supported)]
+#[derive(Diagnostic)]
+#[diag(session_sanitizers_not_supported)]
pub struct SanitizersNotSupported {
pub us: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(session::cannot_mix_and_match_sanitizers)]
+#[derive(Diagnostic)]
+#[diag(session_cannot_mix_and_match_sanitizers)]
pub struct CannotMixAndMatchSanitizers {
pub first: String,
pub second: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(session::cannot_enable_crt_static_linux)]
+#[derive(Diagnostic)]
+#[diag(session_cannot_enable_crt_static_linux)]
pub struct CannotEnableCrtStaticLinux;
-#[derive(SessionDiagnostic)]
-#[diag(session::sanitizer_cfi_enabled)]
+#[derive(Diagnostic)]
+#[diag(session_sanitizer_cfi_enabled)]
pub struct SanitizerCfiEnabled;
-#[derive(SessionDiagnostic)]
-#[diag(session::unstable_virtual_function_elimination)]
+#[derive(Diagnostic)]
+#[diag(session_unstable_virtual_function_elimination)]
pub struct UnstableVirtualFunctionElimination;
-#[derive(SessionDiagnostic)]
-#[diag(session::unsupported_dwarf_version)]
+#[derive(Diagnostic)]
+#[diag(session_unsupported_dwarf_version)]
pub struct UnsupportedDwarfVersion {
pub dwarf_version: u32,
}
-#[derive(SessionDiagnostic)]
-#[diag(session::target_stack_protector_not_supported)]
+#[derive(Diagnostic)]
+#[diag(session_target_stack_protector_not_supported)]
pub struct StackProtectorNotSupportedForTarget<'a> {
pub stack_protector: StackProtector,
pub target_triple: &'a TargetTriple,
}
-#[derive(SessionDiagnostic)]
-#[diag(session::split_debuginfo_unstable_platform)]
+#[derive(Diagnostic)]
+#[diag(session_split_debuginfo_unstable_platform)]
pub struct SplitDebugInfoUnstablePlatform {
pub debuginfo: SplitDebuginfo,
}
-#[derive(SessionDiagnostic)]
-#[diag(session::file_is_not_writeable)]
+#[derive(Diagnostic)]
+#[diag(session_file_is_not_writeable)]
pub struct FileIsNotWriteable<'a> {
pub file: &'a std::path::Path,
}
-#[derive(SessionDiagnostic)]
-#[diag(session::crate_name_does_not_match)]
+#[derive(Diagnostic)]
+#[diag(session_crate_name_does_not_match)]
pub struct CrateNameDoesNotMatch<'a> {
#[primary_span]
pub span: Span,
@@ -186,36 +133,61 @@ pub struct CrateNameDoesNotMatch<'a> {
pub name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(session::crate_name_invalid)]
+#[derive(Diagnostic)]
+#[diag(session_crate_name_invalid)]
pub struct CrateNameInvalid<'a> {
pub s: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(session::crate_name_empty)]
+#[derive(Diagnostic)]
+#[diag(session_crate_name_empty)]
pub struct CrateNameEmpty {
#[primary_span]
pub span: Option<Span>,
}
+#[derive(Diagnostic)]
+#[diag(session_invalid_character_in_create_name)]
pub struct InvalidCharacterInCrateName<'a> {
+ #[primary_span]
pub span: Option<Span>,
pub character: char,
pub crate_name: &'a str,
}
-impl crate::SessionDiagnostic<'_> for InvalidCharacterInCrateName<'_> {
- fn into_diagnostic(
- self,
- sess: &Handler,
- ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
- let mut diag = sess.struct_err(fluent::session::invalid_character_in_create_name);
- if let Some(sp) = self.span {
- diag.set_span(sp);
- }
- diag.set_arg("character", self.character);
- diag.set_arg("crate_name", self.crate_name);
- diag
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(session_expr_parentheses_needed, applicability = "machine-applicable")]
+pub struct ExprParenthesesNeeded {
+ #[suggestion_part(code = "(")]
+ pub left: Span,
+ #[suggestion_part(code = ")")]
+ pub right: Span,
+}
+
+impl ExprParenthesesNeeded {
+ pub fn surrounding(s: Span) -> Self {
+ ExprParenthesesNeeded { left: s.shrink_to_lo(), right: s.shrink_to_hi() }
}
}
+
+#[derive(Diagnostic)]
+#[diag(session_skipping_const_checks)]
+pub struct SkippingConstChecks {
+ #[subdiagnostic(eager)]
+ pub unleashed_features: Vec<UnleashedFeatureHelp>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum UnleashedFeatureHelp {
+ #[help(session_unleashed_feature_help_named)]
+ Named {
+ #[primary_span]
+ span: Span,
+ gate: Symbol,
+ },
+ #[help(session_unleashed_feature_help_unnamed)]
+ Unnamed {
+ #[primary_span]
+ span: Span,
+ },
+}
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index f6bab775e..39e871f53 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -1,6 +1,5 @@
#![feature(if_let_guard)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(once_cell)]
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index d7f1bc0be..3f234a47a 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -186,7 +186,7 @@ top_level_options!(
/// Remap source path prefixes in all output (messages, object files, debug, etc.).
remap_path_prefix: Vec<(PathBuf, PathBuf)> [TRACKED_NO_CRATE_HASH],
/// Base directory containing the `src/` for the Rust standard library, and
- /// potentially `rustc` as well, if we can can find it. Right now it's always
+ /// potentially `rustc` as well, if we can find it. Right now it's always
/// `$sysroot/lib/rustlib/src/rust` (i.e. the `rustup` `rust-src` component).
///
/// This directory is what the virtual `/rustc/$hash` is translated back to,
@@ -280,14 +280,6 @@ macro_rules! options {
) }
-impl Options {
- // JUSTIFICATION: defn of the suggested wrapper fn
- #[allow(rustc::bad_opt_access)]
- pub fn time_passes(&self) -> bool {
- self.unstable_opts.time_passes || self.unstable_opts.time
- }
-}
-
impl CodegenOptions {
// JUSTIFICATION: defn of the suggested wrapper fn
#[allow(rustc::bad_opt_access)]
@@ -1083,12 +1075,11 @@ mod parse {
options! {
CodegenOptions, CG_OPTIONS, cgopts, "C", "codegen",
- // This list is in alphabetical order.
- //
// If you add a new option, please update:
// - compiler/rustc_interface/src/tests.rs
// - src/doc/rustc/src/codegen-options/index.md
+ // tidy-alphabetical-start
ar: String = (String::new(), parse_string, [UNTRACKED],
"this option is deprecated and does nothing"),
#[rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field")]
@@ -1203,9 +1194,8 @@ options! {
target_feature: String = (String::new(), parse_target_feature, [TRACKED],
"target specific attributes. (`rustc --print target-features` for details). \
This feature is unsafe."),
+ // tidy-alphabetical-end
- // This list is in alphabetical order.
- //
// If you add a new option, please update:
// - compiler/rustc_interface/src/tests.rs
// - src/doc/rustc/src/codegen-options/index.md
@@ -1214,24 +1204,23 @@ options! {
options! {
UnstableOptions, Z_OPTIONS, dbopts, "Z", "unstable",
- // This list is in alphabetical order.
- //
// If you add a new option, please update:
// - compiler/rustc_interface/src/tests.rs
// - src/doc/unstable-book/src/compiler-flags
+ // tidy-alphabetical-start
allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
"only allow the listed language features to be enabled in code (space separated)"),
always_encode_mir: bool = (false, parse_bool, [TRACKED],
"encode MIR of all functions into the crate metadata (default: no)"),
- assume_incomplete_release: bool = (false, parse_bool, [TRACKED],
- "make cfg(version) treat the current version as incomplete (default: no)"),
#[rustc_lint_opt_deny_field_access("use `Session::asm_comments` instead of this field")]
asm_comments: bool = (false, parse_bool, [TRACKED],
"generate comments into the assembly (may change behavior) (default: no)"),
assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED],
"assert that the incremental cache is in given state: \
either `loaded` or `not-loaded`."),
+ assume_incomplete_release: bool = (false, parse_bool, [TRACKED],
+ "make cfg(version) treat the current version as incomplete (default: no)"),
#[rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field")]
binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
"include artifacts (sysroot, crate dependencies) used during compilation in dep-info \
@@ -1264,6 +1253,8 @@ options! {
dep_tasks: bool = (false, parse_bool, [UNTRACKED],
"print tasks that execute and the color their dep node gets (requires debug build) \
(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],
@@ -1304,6 +1295,8 @@ options! {
an additional `.html` file showing the computed coverage spans."),
dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
+ dylib_lto: bool = (false, parse_bool, [UNTRACKED],
+ "enables LTO for dylib crate type"),
emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
"emit a section containing stack size metadata (default: no)"),
emit_thin_lto: bool = (true, parse_bool, [TRACKED],
@@ -1345,16 +1338,16 @@ options! {
"hash spans relative to their parent item for incr. comp. (default: no)"),
incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
"verify incr. comp. hashes of green query instances (default: no)"),
+ inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
+ "control whether `#[inline]` functions are in all CGUs"),
inline_llvm: bool = (true, parse_bool, [TRACKED],
"enable LLVM inlining (default: yes)"),
inline_mir: Option<bool> = (None, parse_opt_bool, [TRACKED],
"enable MIR inlining (default: no)"),
- inline_mir_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
- "a default MIR inlining threshold (default: 50)"),
inline_mir_hint_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
"inlining threshold for functions with inline hint (default: 100)"),
- inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
- "control whether `#[inline]` functions are in all CGUs"),
+ inline_mir_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
+ "a default MIR inlining threshold (default: 50)"),
input_stats: bool = (false, parse_bool, [UNTRACKED],
"gather statistics about the input (default: no)"),
#[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")]
@@ -1371,6 +1364,8 @@ options! {
"insert function instrument code for mcount-based tracing (default: no)"),
keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
"keep hygiene data after analysis (default: no)"),
+ layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED],
+ "seed layout randomization"),
link_native_libraries: bool = (true, parse_bool, [UNTRACKED],
"link native libraries in the linker invocation (default: yes)"),
link_only: bool = (false, parse_bool, [TRACKED],
@@ -1400,17 +1395,15 @@ options! {
"use like `-Zmir-enable-passes=+DestProp,-InstCombine`. 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_pretty_relative_line_numbers: bool = (false, parse_bool, [UNTRACKED],
- "use line numbers relative to the function in mir pretty printing"),
#[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)"),
+ mir_pretty_relative_line_numbers: bool = (false, parse_bool, [UNTRACKED],
+ "use line numbers relative to the function in mir pretty printing"),
move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
"the size at which the `large_assignments` lint starts to be emitted"),
mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
"emit noalias metadata for mutable references (default: yes)"),
- new_llvm_pass_manager: Option<bool> = (None, parse_opt_bool, [TRACKED],
- "use new LLVM pass manager (default: no)"),
nll_facts: bool = (false, parse_bool, [UNTRACKED],
"dump facts from NLL analysis into side files (default: no)"),
nll_facts_dir: String = ("nll-facts".to_string(), parse_string, [UNTRACKED],
@@ -1429,18 +1422,16 @@ options! {
"compile without linking"),
no_parallel_llvm: bool = (false, parse_no_flag, [UNTRACKED],
"run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
- no_unique_section_names: bool = (false, parse_bool, [TRACKED],
- "do not use unique names for text and data sections when -Z function-sections is used"),
no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED],
"prevent automatic injection of the profiler_builtins crate"),
+ no_unique_section_names: bool = (false, parse_bool, [TRACKED],
+ "do not use unique names for text and data sections when -Z function-sections is used"),
normalize_docs: bool = (false, parse_bool, [TRACKED],
"normalize associated items in rustdoc when generating documentation"),
oom: OomStrategy = (OomStrategy::Abort, parse_oom_strategy, [TRACKED],
"panic strategy for out-of-memory handling"),
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
"pass `-install_name @rpath/...` to the macOS linker (default: no)"),
- diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
- "set the current output width for diagnostic truncation"),
packed_bundled_libs: bool = (false, parse_bool, [TRACKED],
"change rlib format to store native libraries as archives"),
panic_abort_tests: bool = (false, parse_bool, [TRACKED],
@@ -1490,25 +1481,20 @@ options! {
profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
"file path to emit profiling data at runtime when using 'profile' \
(default based on relative source path)"),
- profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED],
- "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"),
profile_sample_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
"use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"),
+ profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED],
+ "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"),
query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
"enable queries of the dependency graph for regression testing (default: no)"),
randomize_layout: bool = (false, parse_bool, [TRACKED],
"randomize the layout of types (default: no)"),
- layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED],
- "seed layout randomization"),
relax_elf_relocations: Option<bool> = (None, parse_opt_bool, [TRACKED],
"whether ELF relocations can be relaxed"),
relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
"choose which RELRO level to use"),
remap_cwd_prefix: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
"remap paths under the current working directory to this path prefix"),
- simulate_remapped_rust_src_base: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
- "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \
- to rust's source base directory. only meant for testing purposes"),
report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
"immediately print bugs registered with `delay_span_bug` (default: no)"),
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
@@ -1526,27 +1512,41 @@ options! {
self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
parse_switch_with_opt_path, [UNTRACKED],
"run the self profiler and output the raw event data"),
- /// keep this in sync with the event filter names in librustc_data_structures/profiling.rs
- self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
- "specify the events recorded by the self profiler;
- for example: `-Z self-profile-events=default,query-keys`
- all options: none, all, default, generic-activity, query-provider, query-cache-hit
- query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"),
self_profile_counter: String = ("wall-time".to_string(), parse_string, [UNTRACKED],
"counter used by the self profiler (default: `wall-time`), one of:
`wall-time` (monotonic clock, i.e. `std::time::Instant`)
`instructions:u` (retired instructions, userspace-only)
`instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)"
),
+ /// keep this in sync with the event filter names in librustc_data_structures/profiling.rs
+ self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
+ "specify the events recorded by the self profiler;
+ for example: `-Z self-profile-events=default,query-keys`
+ all options: none, all, default, generic-activity, query-provider, query-cache-hit
+ query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"),
share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
"make the current crate share its generic instantiations"),
show_span: Option<String> = (None, parse_opt_string, [TRACKED],
"show spans for compiler debugging (expr|pat|ty)"),
+ simulate_remapped_rust_src_base: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
+ "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \
+ to rust's source base directory. only meant for testing purposes"),
span_debug: bool = (false, parse_bool, [UNTRACKED],
"forward proc_macro::Span's `Debug` impl to `Span`"),
/// o/w tests have closure@path
span_free_formats: bool = (false, parse_bool, [UNTRACKED],
"exclude spans when debug-printing compiler state (default: no)"),
+ split_dwarf_inlining: bool = (true, parse_bool, [TRACKED],
+ "provide minimal debug info in the object/executable to facilitate online \
+ symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
+ split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [TRACKED],
+ "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
+ (default: `split`)
+
+ `split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
+ file which is ignored by the linker
+ `single`: sections which do not require relocation are written into object file but ignored
+ by the linker"),
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")]
@@ -1556,17 +1556,6 @@ options! {
"control if mem::uninitialized and mem::zeroed panic on more UB"),
strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
"tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
- split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [TRACKED],
- "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
- (default: `split`)
-
- `split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
- 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_dwarf_inlining: bool = (true, parse_bool, [TRACKED],
- "provide minimal debug info in the object/executable to facilitate online \
- symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
symbol_mangling_version: Option<SymbolManglingVersion> = (None,
parse_symbol_mangling_version, [TRACKED],
"which mangling version to use for symbol names ('legacy' (default) or 'v0')"),
@@ -1575,17 +1564,6 @@ options! {
"show extended diagnostic help (default: no)"),
temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
"the directory the intermediate files are written to"),
- // Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved
- // alongside query results and changes to translation options can affect diagnostics - so
- // translation options should be tracked.
- translate_lang: Option<LanguageIdentifier> = (None, parse_opt_langid, [TRACKED],
- "language identifier for diagnostic output"),
- translate_additional_ftl: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
- "additional fluent translation to preferentially use (for testing translation)"),
- translate_directionality_markers: bool = (false, parse_bool, [TRACKED],
- "emit directionality isolation markers in translated diagnostics"),
- tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
- "select processor to schedule for (`rustc --print target-cpus` for details)"),
#[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
"enable ThinLTO when possible"),
@@ -1598,9 +1576,6 @@ options! {
#[rustc_lint_opt_deny_field_access("use `Session::threads` instead of this field")]
threads: usize = (1, parse_threads, [UNTRACKED],
"use a thread pool with N threads"),
- #[rustc_lint_opt_deny_field_access("use `Session::time_passes` instead of this field")]
- time: bool = (false, parse_bool, [UNTRACKED],
- "measure time of rustc processes (default: no)"),
#[rustc_lint_opt_deny_field_access("use `Session::time_llvm_passes` instead of this field")]
time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
"measure time of each LLVM pass (default: no)"),
@@ -1612,6 +1587,15 @@ options! {
"choose the TLS model to use (`rustc --print tls-models` for details)"),
trace_macros: bool = (false, parse_bool, [UNTRACKED],
"for every macro invocation, print its name and arguments (default: no)"),
+ // Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved
+ // alongside query results and changes to translation options can affect diagnostics - so
+ // translation options should be tracked.
+ translate_additional_ftl: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
+ "additional fluent translation to preferentially use (for testing translation)"),
+ translate_directionality_markers: bool = (false, parse_bool, [TRACKED],
+ "emit directionality isolation markers in translated diagnostics"),
+ translate_lang: Option<LanguageIdentifier> = (None, parse_opt_langid, [TRACKED],
+ "language identifier for diagnostic output"),
translate_remapped_path_to_local_path: bool = (true, parse_bool, [TRACKED],
"translate remapped paths into local paths when possible (default: yes)"),
trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
@@ -1620,6 +1604,8 @@ options! {
"treat error number `val` that occurs as bug"),
trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
"in diagnostics, use heuristics to shorten paths referring to items"),
+ tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
+ "select processor to schedule for (`rustc --print target-cpus` for details)"),
ui_testing: bool = (false, parse_bool, [UNTRACKED],
"emit compiler diagnostics in a form suitable for UI testing (default: no)"),
uninit_const_chunk_threshold: usize = (16, parse_number, [TRACKED],
@@ -1660,9 +1646,8 @@ options! {
Requires `-Clto[=[fat,yes]]`"),
wasi_exec_model: Option<WasiExecModel> = (None, parse_wasi_exec_model, [TRACKED],
"whether to build a wasi command or reactor"),
+ // tidy-alphabetical-end
- // This list is in alphabetical order.
- //
// If you add a new option, please update:
// - compiler/rustc_interface/src/tests.rs
}
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 0389b2a06..a199947eb 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -6,14 +6,13 @@ use crate::errors::{FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGat
use crate::lint::{
builtin::UNSTABLE_SYNTAX_PRE_EXPANSION, BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId,
};
-use crate::SessionDiagnostic;
use rustc_ast::node_id::NodeId;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_data_structures::sync::{Lock, Lrc};
use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
use rustc_errors::{
- fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId,
- DiagnosticMessage, EmissionGuarantee, ErrorGuaranteed, MultiSpan, StashKey,
+ fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
+ EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, Noted, StashKey,
};
use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
use rustc_span::edition::Edition;
@@ -323,16 +322,6 @@ impl ParseSess {
});
}
- /// Extend an error with a suggestion to wrap an expression with parentheses to allow the
- /// parser to continue parsing the following operation as part of the same expression.
- pub fn expr_parentheses_needed(&self, err: &mut Diagnostic, span: Span) {
- err.multipart_suggestion(
- "parentheses are required to parse this as an expression",
- vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), ")".to_string())],
- Applicability::MachineApplicable,
- );
- }
-
pub fn save_proc_macro_span(&self, span: Span) -> usize {
let mut spans = self.proc_macro_quoted_spans.lock();
spans.push(span);
@@ -345,40 +334,49 @@ impl ParseSess {
pub fn create_err<'a>(
&'a self,
- err: impl SessionDiagnostic<'a>,
+ err: impl IntoDiagnostic<'a>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
err.into_diagnostic(&self.span_diagnostic)
}
- pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed {
+ pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
self.create_err(err).emit()
}
pub fn create_warning<'a>(
&'a self,
- warning: impl SessionDiagnostic<'a, ()>,
+ warning: impl IntoDiagnostic<'a, ()>,
) -> DiagnosticBuilder<'a, ()> {
warning.into_diagnostic(&self.span_diagnostic)
}
- pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) {
+ pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
self.create_warning(warning).emit()
}
+ pub fn create_note<'a>(
+ &'a self,
+ note: impl IntoDiagnostic<'a, Noted>,
+ ) -> DiagnosticBuilder<'a, Noted> {
+ note.into_diagnostic(&self.span_diagnostic)
+ }
+
+ pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted {
+ self.create_note(note).emit()
+ }
+
pub fn create_fatal<'a>(
&'a self,
- fatal: impl SessionDiagnostic<'a, !>,
+ fatal: impl IntoDiagnostic<'a, !>,
) -> DiagnosticBuilder<'a, !> {
fatal.into_diagnostic(&self.span_diagnostic)
}
- pub fn emit_fatal<'a>(&'a self, fatal: impl SessionDiagnostic<'a, !>) -> ! {
+ pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! {
self.create_fatal(fatal).emit()
}
#[rustc_lint_diagnostics]
- #[allow(rustc::diagnostic_outside_of_impl)]
- #[allow(rustc::untranslatable_diagnostic)]
pub fn struct_err(
&self,
msg: impl Into<DiagnosticMessage>,
@@ -387,22 +385,16 @@ impl ParseSess {
}
#[rustc_lint_diagnostics]
- #[allow(rustc::diagnostic_outside_of_impl)]
- #[allow(rustc::untranslatable_diagnostic)]
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
self.span_diagnostic.struct_warn(msg)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::diagnostic_outside_of_impl)]
- #[allow(rustc::untranslatable_diagnostic)]
pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
self.span_diagnostic.struct_fatal(msg)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::diagnostic_outside_of_impl)]
- #[allow(rustc::untranslatable_diagnostic)]
pub fn struct_diagnostic<G: EmissionGuarantee>(
&self,
msg: impl Into<DiagnosticMessage>,
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index a001f87db..100c66f63 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -5,9 +5,10 @@ use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, S
use crate::errors::{
CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers, LinkerPluginToWindowsNotSupported,
NotCircumventFeature, ProfileSampleUseFileDoesNotExist, ProfileUseFileDoesNotExist,
- SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported,
+ SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported, SkippingConstChecks,
SplitDebugInfoUnstablePlatform, StackProtectorNotSupportedForTarget,
- TargetRequiresUnwindTables, UnstableVirtualFunctionElimination, UnsupportedDwarfVersion,
+ TargetRequiresUnwindTables, UnleashedFeatureHelp, UnstableVirtualFunctionElimination,
+ UnsupportedDwarfVersion,
};
use crate::parse::{add_feature_diagnostics, ParseSess};
use crate::search_paths::{PathKind, SearchPath};
@@ -28,7 +29,7 @@ use rustc_errors::json::JsonEmitter;
use rustc_errors::registry::Registry;
use rustc_errors::{
error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
- EmissionGuarantee, ErrorGuaranteed, FluentBundle, Handler, LazyFallbackBundle, MultiSpan,
+ ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted,
};
use rustc_macros::HashStable_Generic;
pub use rustc_span::def_id::StableCrateId;
@@ -44,7 +45,6 @@ use rustc_target::spec::{
use std::cell::{self, RefCell};
use std::env;
use std::fmt;
-use std::io::Write;
use std::ops::{Div, Mul};
use std::path::{Path, PathBuf};
use std::str::FromStr;
@@ -223,15 +223,6 @@ pub struct PerfStats {
pub normalize_projection_ty: AtomicUsize,
}
-/// Trait implemented by error types. This should not be implemented manually. Instead, use
-/// `#[derive(SessionDiagnostic)]` -- see [rustc_macros::SessionDiagnostic].
-#[rustc_diagnostic_item = "SessionDiagnostic"]
-pub trait SessionDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> {
- /// Write out as a diagnostic out of `Handler`.
- #[must_use]
- fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, T>;
-}
-
impl Session {
pub fn miri_unleashed_feature(&self, span: Span, feature_gate: Option<Symbol>) {
self.miri_unleashed_features.lock().push((span, feature_gate));
@@ -242,21 +233,19 @@ impl Session {
if !unleashed_features.is_empty() {
let mut must_err = false;
// Create a diagnostic pointing at where things got unleashed.
- // FIXME(#100717): needs eager translation/lists
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
- let mut diag = self.struct_warn("skipping const checks");
- for &(span, feature_gate) in unleashed_features.iter() {
- // FIXME: `span_label` doesn't do anything, so we use "help" as a hack.
- if let Some(gate) = feature_gate {
- diag.span_help(span, &format!("skipping check for `{gate}` feature"));
- // The unleash flag must *not* be used to just "hack around" feature gates.
- must_err = true;
- } else {
- diag.span_help(span, "skipping check that does not even have a feature gate");
- }
- }
- diag.emit();
+ self.emit_warning(SkippingConstChecks {
+ unleashed_features: unleashed_features
+ .iter()
+ .map(|(span, gate)| {
+ gate.map(|gate| {
+ must_err = true;
+ UnleashedFeatureHelp::Named { span: *span, gate }
+ })
+ .unwrap_or(UnleashedFeatureHelp::Unnamed { span: *span })
+ })
+ .collect(),
+ });
+
// If we should err, make sure we did.
if must_err && self.has_errors().is_none() {
// We have skipped a feature gate, and not run into other errors... reject.
@@ -297,8 +286,6 @@ impl Session {
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_span_warn<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -307,8 +294,6 @@ impl Session {
self.diagnostic().struct_span_warn(sp, msg)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_span_warn_with_expectation<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -318,8 +303,6 @@ impl Session {
self.diagnostic().struct_span_warn_with_expectation(sp, msg, id)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -329,14 +312,10 @@ impl Session {
self.diagnostic().struct_span_warn_with_code(sp, msg, code)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_warn(msg)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_warn_with_expectation(
&self,
msg: impl Into<DiagnosticMessage>,
@@ -345,8 +324,6 @@ impl Session {
self.diagnostic().struct_warn_with_expectation(msg, id)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_span_allow<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -355,14 +332,10 @@ impl Session {
self.diagnostic().struct_span_allow(sp, msg)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_allow(msg)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_expect(
&self,
msg: impl Into<DiagnosticMessage>,
@@ -371,8 +344,6 @@ impl Session {
self.diagnostic().struct_expect(msg, id)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_span_err<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -381,8 +352,6 @@ impl Session {
self.diagnostic().struct_span_err(sp, msg)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_span_err_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -393,8 +362,6 @@ impl Session {
}
// FIXME: This method should be removed (every error should have an associated error code).
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_err(
&self,
msg: impl Into<DiagnosticMessage>,
@@ -402,8 +369,6 @@ impl Session {
self.parse_sess.struct_err(msg)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_err_with_code(
&self,
msg: impl Into<DiagnosticMessage>,
@@ -412,8 +377,6 @@ impl Session {
self.diagnostic().struct_err_with_code(msg, code)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_warn_with_code(
&self,
msg: impl Into<DiagnosticMessage>,
@@ -422,8 +385,6 @@ impl Session {
self.diagnostic().struct_warn_with_code(msg, code)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_span_fatal<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -432,8 +393,6 @@ impl Session {
self.diagnostic().struct_span_fatal(sp, msg)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -443,21 +402,15 @@ impl Session {
self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
self.diagnostic().struct_fatal(msg)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
self.diagnostic().span_fatal(sp, msg)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn span_fatal_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -467,14 +420,10 @@ impl Session {
self.diagnostic().span_fatal_with_code(sp, msg, code)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
self.diagnostic().fatal(msg).raise()
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn span_err_or_warn<S: Into<MultiSpan>>(
&self,
is_warning: bool,
@@ -488,8 +437,6 @@ impl Session {
}
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn span_err<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -498,8 +445,6 @@ impl Session {
self.diagnostic().span_err(sp, msg)
}
#[rustc_lint_diagnostics]
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
pub fn span_err_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -514,13 +459,13 @@ impl Session {
}
pub fn create_err<'a>(
&'a self,
- err: impl SessionDiagnostic<'a>,
+ err: impl IntoDiagnostic<'a>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
self.parse_sess.create_err(err)
}
pub fn create_feature_err<'a>(
&'a self,
- err: impl SessionDiagnostic<'a>,
+ err: impl IntoDiagnostic<'a>,
feature: Symbol,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut err = self.parse_sess.create_err(err);
@@ -530,25 +475,34 @@ impl Session {
add_feature_diagnostics(&mut err, &self.parse_sess, feature);
err
}
- pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed {
+ pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
self.parse_sess.emit_err(err)
}
pub fn create_warning<'a>(
&'a self,
- err: impl SessionDiagnostic<'a, ()>,
+ err: impl IntoDiagnostic<'a, ()>,
) -> DiagnosticBuilder<'a, ()> {
self.parse_sess.create_warning(err)
}
- pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) {
+ pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
self.parse_sess.emit_warning(warning)
}
+ pub fn create_note<'a>(
+ &'a self,
+ note: impl IntoDiagnostic<'a, Noted>,
+ ) -> DiagnosticBuilder<'a, Noted> {
+ self.parse_sess.create_note(note)
+ }
+ pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted {
+ self.parse_sess.emit_note(note)
+ }
pub fn create_fatal<'a>(
&'a self,
- fatal: impl SessionDiagnostic<'a, !>,
+ fatal: impl IntoDiagnostic<'a, !>,
) -> DiagnosticBuilder<'a, !> {
self.parse_sess.create_fatal(fatal)
}
- pub fn emit_fatal<'a>(&'a self, fatal: impl SessionDiagnostic<'a, !>) -> ! {
+ pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! {
self.parse_sess.emit_fatal(fatal)
}
#[inline]
@@ -659,10 +613,6 @@ impl Session {
self.parse_sess.source_map()
}
- pub fn time_passes(&self) -> bool {
- self.opts.time_passes()
- }
-
/// Returns `true` if internal lints should be added to the lint store - i.e. if
/// `-Zunstable-options` is provided and this isn't rustdoc (internal lints can trigger errors
/// to be emitted under rustdoc).
@@ -980,6 +930,10 @@ impl Session {
self.opts.unstable_opts.instrument_mcount
}
+ pub fn time_passes(&self) -> bool {
+ self.opts.unstable_opts.time_passes
+ }
+
pub fn time_llvm_passes(&self) -> bool {
self.opts.unstable_opts.time_llvm_passes
}
@@ -1257,11 +1211,10 @@ fn default_emitter(
source_map: Lrc<SourceMap>,
bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: LazyFallbackBundle,
- emitter_dest: Option<Box<dyn Write + Send>>,
) -> Box<dyn Emitter + sync::Send> {
let macro_backtrace = sopts.unstable_opts.macro_backtrace;
- match (sopts.error_format, emitter_dest) {
- (config::ErrorOutputType::HumanReadable(kind), dst) => {
+ match sopts.error_format {
+ config::ErrorOutputType::HumanReadable(kind) => {
let (short, color_config) = kind.unzip();
if let HumanReadableErrorType::AnnotateSnippet(_) = kind {
@@ -1274,33 +1227,20 @@ fn default_emitter(
);
Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
} else {
- let emitter = match dst {
- None => EmitterWriter::stderr(
- color_config,
- Some(source_map),
- bundle,
- fallback_bundle,
- short,
- sopts.unstable_opts.teach,
- sopts.diagnostic_width,
- macro_backtrace,
- ),
- Some(dst) => EmitterWriter::new(
- dst,
- Some(source_map),
- bundle,
- fallback_bundle,
- short,
- false, // no teach messages when writing to a buffer
- false, // no colors when writing to a buffer
- None, // no diagnostic width
- macro_backtrace,
- ),
- };
+ let emitter = EmitterWriter::stderr(
+ color_config,
+ Some(source_map),
+ bundle,
+ fallback_bundle,
+ short,
+ sopts.unstable_opts.teach,
+ sopts.diagnostic_width,
+ macro_backtrace,
+ );
Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
}
}
- (config::ErrorOutputType::Json { pretty, json_rendered }, None) => Box::new(
+ config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(
JsonEmitter::stderr(
Some(registry),
source_map,
@@ -1313,28 +1253,9 @@ fn default_emitter(
)
.ui_testing(sopts.unstable_opts.ui_testing),
),
- (config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new(
- JsonEmitter::new(
- dst,
- Some(registry),
- source_map,
- bundle,
- fallback_bundle,
- pretty,
- json_rendered,
- sopts.diagnostic_width,
- macro_backtrace,
- )
- .ui_testing(sopts.unstable_opts.ui_testing),
- ),
}
}
-pub enum DiagnosticOutput {
- Default,
- Raw(Box<dyn Write + Send>),
-}
-
// JUSTIFICATION: literally session construction
#[allow(rustc::bad_opt_access)]
pub fn build_session(
@@ -1342,7 +1263,6 @@ pub fn build_session(
local_crate_source_file: Option<PathBuf>,
bundle: Option<Lrc<rustc_errors::FluentBundle>>,
registry: rustc_errors::registry::Registry,
- diagnostics_output: DiagnosticOutput,
driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
target_override: Option<Target>,
@@ -1358,11 +1278,6 @@ pub fn build_session(
let cap_lints_allow = sopts.lint_cap.map_or(false, |cap| cap == lint::Allow);
let can_emit_warnings = !(warnings_allow || cap_lints_allow);
- let write_dest = match diagnostics_output {
- DiagnosticOutput::Default => None,
- DiagnosticOutput::Raw(write) => Some(write),
- };
-
let sysroot = match &sopts.maybe_sysroot {
Some(sysroot) => sysroot.clone(),
None => filesearch::get_or_default_sysroot(),
@@ -1395,8 +1310,7 @@ pub fn build_session(
rustc_errors::DEFAULT_LOCALE_RESOURCES,
sopts.unstable_opts.translate_directionality_markers,
);
- let emitter =
- default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle, write_dest);
+ let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle);
let span_diagnostic = rustc_errors::Handler::with_emitter_and_flags(
emitter,
@@ -1456,8 +1370,7 @@ pub fn build_session(
CguReuseTracker::new_disabled()
};
- let prof =
- SelfProfilerRef::new(self_profiler, sopts.time_passes(), sopts.unstable_opts.time_passes);
+ let prof = SelfProfilerRef::new(self_profiler, sopts.unstable_opts.time_passes);
let ctfe_backtrace = Lock::new(match env::var("RUSTC_CTFE_BACKTRACE") {
Ok(ref val) if val == "immediate" => CtfeBacktrace::Immediate,
diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs
index 9a4f6f9f9..e65b6891e 100644
--- a/compiler/rustc_session/src/utils.rs
+++ b/compiler/rustc_session/src/utils.rs
@@ -53,6 +53,17 @@ impl NativeLibKind {
NativeLibKind::RawDylib | NativeLibKind::Unspecified | NativeLibKind::LinkArg => false,
}
}
+
+ pub fn is_statically_included(&self) -> bool {
+ matches!(self, NativeLibKind::Static { .. })
+ }
+
+ pub fn is_dllimport(&self) -> bool {
+ matches!(
+ self,
+ NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified
+ )
+ }
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml
index 7227b193f..48a2ab0f9 100644
--- a/compiler/rustc_span/Cargo.toml
+++ b/compiler/rustc_span/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
rustc_serialize = { path = "../rustc_serialize" }
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index 37b8371a8..bbeabdb55 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -218,7 +218,9 @@ impl<D: Decoder> Decodable<D> for DefIndex {
/// index and a def index.
///
/// You can create a `DefId` from a `LocalDefId` using `local_def_id.to_def_id()`.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
+#[derive(Clone, PartialEq, Eq, Copy)]
+// Don't derive order on 64-bit big-endian, so we can be consistent regardless of field order.
+#[cfg_attr(not(all(target_pointer_width = "64", target_endian = "big")), derive(PartialOrd, Ord))]
// On below-64 bit systems we can simply use the derived `Hash` impl
#[cfg_attr(not(target_pointer_width = "64"), derive(Hash))]
#[repr(C)]
@@ -260,6 +262,22 @@ impl Hash for DefId {
}
}
+// Implement the same comparison as derived with the other field order.
+#[cfg(all(target_pointer_width = "64", target_endian = "big"))]
+impl Ord for DefId {
+ #[inline]
+ fn cmp(&self, other: &DefId) -> std::cmp::Ordering {
+ Ord::cmp(&(self.index, self.krate), &(other.index, other.krate))
+ }
+}
+#[cfg(all(target_pointer_width = "64", target_endian = "big"))]
+impl PartialOrd for DefId {
+ #[inline]
+ fn partial_cmp(&self, other: &DefId) -> Option<std::cmp::Ordering> {
+ Some(Ord::cmp(self, other))
+ }
+}
+
impl DefId {
/// Makes a local `DefId` from the given `DefIndex`.
#[inline]
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index da31b3462..322c7104b 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -15,7 +15,6 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(array_windows)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(if_let_guard)]
#![feature(negative_impls)]
#![feature(min_specialization)]
@@ -299,7 +298,11 @@ impl From<PathBuf> for FileName {
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum FileNameDisplayPreference {
+ /// Display the path after the application of rewrite rules provided via `--remap-path-prefix`.
+ /// This is appropriate for paths that get embedded into files produced by the compiler.
Remapped,
+ /// Display the path before the application of rewrite rules provided via `--remap-path-prefix`.
+ /// This is appropriate for use in user-facing output (such as diagnostics).
Local,
}
@@ -533,9 +536,6 @@ impl Span {
self.data().with_hi(hi)
}
#[inline]
- pub fn ctxt(self) -> SyntaxContext {
- self.data_untracked().ctxt
- }
pub fn eq_ctxt(self, other: Span) -> bool {
self.data_untracked().ctxt == other.data_untracked().ctxt
}
@@ -1637,11 +1637,7 @@ impl SourceFile {
/// number. If the source_file is empty or the position is located before the
/// first line, `None` is returned.
pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
- self.lines(|lines| match lines.binary_search(&pos) {
- Ok(idx) => Some(idx),
- Err(0) => None,
- Err(idx) => Some(idx - 1),
- })
+ self.lines(|lines| lines.partition_point(|x| x <= &pos).checked_sub(1))
}
pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 4d94c92d3..f9566eeee 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -853,28 +853,56 @@ impl SourceMap {
}
/// Returns a new span representing the next character after the end-point of this span.
+ /// Special cases:
+ /// - if span is a dummy one, returns the same span
+ /// - if next_point reached the end of source, return span with lo = hi
+ /// - respect multi-byte characters
pub fn next_point(&self, sp: Span) -> Span {
if sp.is_dummy() {
return sp;
}
let start_of_next_point = sp.hi().0;
- let width = self.find_width_of_character_at_span(sp.shrink_to_hi(), true);
- // If the width is 1, then the next span should point to the same `lo` and `hi`. However,
- // in the case of a multibyte character, where the width != 1, the next span should
+ let width = self.find_width_of_character_at_span(sp, true);
+ if width == 0 {
+ return Span::new(sp.hi(), sp.hi(), sp.ctxt(), None);
+ }
+ // If the width is 1, then the next span should only contain the next char besides current ending.
+ // However, in the case of a multibyte character, where the width != 1, the next span should
// span multiple bytes to include the whole character.
let end_of_next_point =
- start_of_next_point.checked_add(width - 1).unwrap_or(start_of_next_point);
+ start_of_next_point.checked_add(width).unwrap_or(start_of_next_point);
- let end_of_next_point = BytePos(cmp::max(sp.lo().0 + 1, end_of_next_point));
+ let end_of_next_point = BytePos(cmp::max(start_of_next_point + 1, end_of_next_point));
Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt(), None)
}
+ /// Returns a new span to check next none-whitespace character or some specified expected character
+ /// If `expect` is none, the first span of non-whitespace character is returned.
+ /// If `expect` presented, the first span of the character `expect` is returned
+ /// Otherwise, the span reached to limit is returned.
+ pub fn span_look_ahead(&self, span: Span, expect: Option<&str>, limit: Option<usize>) -> Span {
+ let mut sp = span;
+ for _ in 0..limit.unwrap_or(100 as usize) {
+ sp = self.next_point(sp);
+ if let Ok(ref snippet) = self.span_to_snippet(sp) {
+ if expect.map_or(false, |es| snippet == es) {
+ break;
+ }
+ if expect.is_none() && snippet.chars().any(|c| !c.is_whitespace()) {
+ break;
+ }
+ }
+ }
+ sp
+ }
+
/// Finds the width of the character, either before or after the end of provided span,
/// depending on the `forwards` parameter.
fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
let sp = sp.data();
- if sp.lo == sp.hi {
+
+ if sp.lo == sp.hi && !forwards {
debug!("find_width_of_character_at_span: early return empty span");
return 1;
}
@@ -908,9 +936,9 @@ impl SourceMap {
let source_len = (local_begin.sf.end_pos - local_begin.sf.start_pos).to_usize();
debug!("find_width_of_character_at_span: source_len=`{:?}`", source_len);
// Ensure indexes are also not malformed.
- if start_index > end_index || end_index > source_len {
+ if start_index > end_index || end_index > source_len - 1 {
debug!("find_width_of_character_at_span: source indexes are malformed");
- return 1;
+ return 0;
}
let src = local_begin.sf.external_src.borrow();
diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs
index 3058ec45a..1fd81018f 100644
--- a/compiler/rustc_span/src/source_map/tests.rs
+++ b/compiler/rustc_span/src/source_map/tests.rs
@@ -479,3 +479,48 @@ fn path_prefix_remapping_expand_to_absolute() {
RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") }
);
}
+
+#[test]
+fn test_next_point() {
+ let sm = SourceMap::new(FilePathMapping::empty());
+ sm.new_source_file(PathBuf::from("example.rs").into(), "a…b".to_string());
+
+ // Dummy spans don't advance.
+ let span = DUMMY_SP;
+ let span = sm.next_point(span);
+ assert_eq!(span.lo().0, 0);
+ assert_eq!(span.hi().0, 0);
+
+ // Span advance respect multi-byte character
+ let span = Span::with_root_ctxt(BytePos(0), BytePos(1));
+ assert_eq!(sm.span_to_snippet(span), Ok("a".to_string()));
+ let span = sm.next_point(span);
+ assert_eq!(sm.span_to_snippet(span), Ok("…".to_string()));
+ assert_eq!(span.lo().0, 1);
+ assert_eq!(span.hi().0, 4);
+
+ // An empty span pointing just before a multi-byte character should
+ // advance to contain the multi-byte character.
+ let span = Span::with_root_ctxt(BytePos(1), BytePos(1));
+ let span = sm.next_point(span);
+ assert_eq!(span.lo().0, 1);
+ assert_eq!(span.hi().0, 4);
+
+ let span = Span::with_root_ctxt(BytePos(1), BytePos(4));
+ let span = sm.next_point(span);
+ assert_eq!(span.lo().0, 4);
+ assert_eq!(span.hi().0, 5);
+
+ // A non-empty span at the last byte should advance to create an empty
+ // span pointing at the end of the file.
+ let span = Span::with_root_ctxt(BytePos(4), BytePos(5));
+ let span = sm.next_point(span);
+ assert_eq!(span.lo().0, 5);
+ assert_eq!(span.hi().0, 5);
+
+ // Empty span pointing just past the last byte.
+ let span = Span::with_root_ctxt(BytePos(5), BytePos(5));
+ let span = sm.next_point(span);
+ assert_eq!(span.lo().0, 5);
+ assert_eq!(span.hi().0, 5);
+}
diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs
index 3ee329e97..b3de67415 100644
--- a/compiler/rustc_span/src/span_encoding.rs
+++ b/compiler/rustc_span/src/span_encoding.rs
@@ -28,12 +28,17 @@ use rustc_data_structures::fx::FxIndexSet;
/// Inline (compressed) format:
/// - `span.base_or_index == span_data.lo`
/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
-/// - `span.ctxt == span_data.ctxt` (must be `<= MAX_CTXT`)
+/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
+///
+/// Interned format with inline `SyntaxContext`:
+/// - `span.base_or_index == index` (indexes into the interner table)
+/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
+/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
///
/// Interned format:
/// - `span.base_or_index == index` (indexes into the interner table)
/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
-/// - `span.ctxt == 0`
+/// - `span.ctxt_or_tag == CTXT_TAG`
///
/// The inline form uses 0 for the tag value (rather than 1) so that we don't
/// need to mask out the tag bit when getting the length, and so that the
@@ -50,10 +55,10 @@ use rustc_data_structures::fx::FxIndexSet;
/// at 3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough
/// for 99.99%+ of cases, but larger values (sometimes 20+ bits) might occur
/// dozens of times in a typical crate.
-/// - `ctxt` is 16 bits in `Span` and 32 bits in `SpanData`, which means that
+/// - `ctxt_or_tag` is 16 bits in `Span` and 32 bits in `SpanData`, which means that
/// large `ctxt` values will cause interning. The number of bits needed for
/// `ctxt` values depend partly on the crate size and partly on the form of
-/// the code. No crates in `rustc-perf` need more than 15 bits for `ctxt`,
+/// the code. No crates in `rustc-perf` need more than 15 bits for `ctxt_or_tag`,
/// but larger crates might need more than 16 bits.
///
/// In order to reliably use parented spans in incremental compilation,
@@ -65,15 +70,16 @@ use rustc_data_structures::fx::FxIndexSet;
pub struct Span {
base_or_index: u32,
len_or_tag: u16,
- ctxt_or_zero: u16,
+ ctxt_or_tag: u16,
}
const LEN_TAG: u16 = 0b1000_0000_0000_0000;
const MAX_LEN: u32 = 0b0111_1111_1111_1111;
-const MAX_CTXT: u32 = 0b1111_1111_1111_1111;
+const CTXT_TAG: u32 = 0b1111_1111_1111_1111;
+const MAX_CTXT: u32 = CTXT_TAG - 1;
/// Dummy span, both position and length are zero, syntax context is zero as well.
-pub const DUMMY_SP: Span = Span { base_or_index: 0, len_or_tag: 0, ctxt_or_zero: 0 };
+pub const DUMMY_SP: Span = Span { base_or_index: 0, len_or_tag: 0, ctxt_or_tag: 0 };
impl Span {
#[inline]
@@ -91,12 +97,13 @@ impl Span {
if len <= MAX_LEN && ctxt2 <= MAX_CTXT && parent.is_none() {
// Inline format.
- Span { base_or_index: base, len_or_tag: len as u16, ctxt_or_zero: ctxt2 as u16 }
+ Span { base_or_index: base, len_or_tag: len as u16, ctxt_or_tag: ctxt2 as u16 }
} else {
// Interned format.
let index =
with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));
- Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_zero: 0 }
+ let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16;
+ Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag }
}
}
@@ -119,16 +126,29 @@ impl Span {
SpanData {
lo: BytePos(self.base_or_index),
hi: BytePos(self.base_or_index + self.len_or_tag as u32),
- ctxt: SyntaxContext::from_u32(self.ctxt_or_zero as u32),
+ ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32),
parent: None,
}
} else {
// Interned format.
- debug_assert!(self.ctxt_or_zero == 0);
let index = self.base_or_index;
with_span_interner(|interner| interner.spans[index as usize])
}
}
+
+ /// This function is used as a fast path when decoding the full `SpanData` is not necessary.
+ #[inline]
+ pub fn ctxt(self) -> SyntaxContext {
+ let ctxt_or_tag = self.ctxt_or_tag as u32;
+ if ctxt_or_tag <= MAX_CTXT {
+ // Inline format or interned 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)
+ }
+ }
}
#[derive(Default)]
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index ae4d1a463..7f16da52b 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -125,7 +125,7 @@ symbols! {
Symbols {
AcqRel,
Acquire,
- AddSubdiagnostic,
+ AddToDiagnostic,
Alignment,
Any,
Arc,
@@ -210,6 +210,7 @@ symbols! {
Implied,
Input,
Into,
+ IntoDiagnostic,
IntoFuture,
IntoIterator,
IoRead,
@@ -223,6 +224,7 @@ symbols! {
Left,
LinkedList,
LintPass,
+ LocalKey,
Mutex,
MutexGuard,
N,
@@ -265,6 +267,7 @@ symbols! {
Rc,
Ready,
Receiver,
+ RefCell,
Relaxed,
Release,
Result,
@@ -273,11 +276,11 @@ symbols! {
Rust,
RustcDecodable,
RustcEncodable,
+ RwLock,
RwLockReadGuard,
RwLockWriteGuard,
Send,
SeqCst,
- SessionDiagnostic,
SliceIndex,
Some,
String,
@@ -396,6 +399,7 @@ symbols! {
assume_init,
async_await,
async_closure,
+ async_fn_in_trait,
atomic,
atomic_mod,
atomics,
@@ -447,6 +451,7 @@ symbols! {
call_once,
caller_location,
capture_disjoint_fields,
+ cause,
cdylib,
ceilf32,
ceilf64,
@@ -781,6 +786,7 @@ symbols! {
globs,
gt,
half_open_range_patterns,
+ half_open_range_patterns_in_slices,
hash,
hexagon_target_feature,
hidden,
@@ -990,7 +996,18 @@ symbols! {
never_type,
never_type_fallback,
new,
+ new_binary,
+ new_debug,
+ new_display,
+ new_lower_exp,
+ new_lower_hex,
+ new_octal,
+ new_pointer,
new_unchecked,
+ new_upper_exp,
+ new_upper_hex,
+ new_v1,
+ new_v1_formatted,
next,
nll,
no,
@@ -1214,9 +1231,7 @@ symbols! {
rust_eh_unregister_frames,
rust_oom,
rustc,
- rustc_access_level,
rustc_allocator,
- rustc_allocator_nounwind,
rustc_allocator_zeroed,
rustc_allow_const_fn_unstable,
rustc_allow_incoherent_impl,
@@ -1242,6 +1257,7 @@ symbols! {
rustc_dump_program_clauses,
rustc_dump_user_substs,
rustc_dump_vtable,
+ rustc_effective_visibility,
rustc_error,
rustc_evaluate_where_clauses,
rustc_expected_cgu_reuse,
@@ -1262,6 +1278,7 @@ symbols! {
rustc_mir,
rustc_must_implement_one_of,
rustc_nonnull_optimization_guaranteed,
+ rustc_nounwind,
rustc_object_lifetime_default,
rustc_on_unimplemented,
rustc_outlives,
@@ -1281,6 +1298,7 @@ symbols! {
rustc_reallocator,
rustc_regions,
rustc_reservation_impl,
+ rustc_safe_intrinsic,
rustc_serialize,
rustc_skip_array_during_method_dispatch,
rustc_specialization_trait,
@@ -1688,6 +1706,7 @@ impl Ident {
/// macro (e.g., `macro` or `macro_rules!` items) and stay different if they came from different
/// non-transparent macros.
/// Technically, this operation strips all transparent marks from ident's syntactic context.
+ #[inline]
pub fn normalize_to_macro_rules(self) -> Ident {
Ident::new(self.name, self.span.normalize_to_macro_rules())
}
@@ -1703,6 +1722,7 @@ impl Ident {
}
impl PartialEq for Ident {
+ #[inline]
fn eq(&self, rhs: &Self) -> bool {
self.name == rhs.name && self.span.eq_ctxt(rhs.span)
}
@@ -1881,6 +1901,13 @@ impl fmt::Display for Symbol {
}
}
+// takes advantage of `str::to_string` specialization
+impl ToString for Symbol {
+ fn to_string(&self) -> String {
+ self.as_str().to_string()
+ }
+}
+
impl<S: Encoder> Encodable<S> for Symbol {
default fn encode(&self, s: &mut S) {
s.emit_str(self.as_str());
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index 3db052257..2a29ad6a9 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
bitflags = "1.2.1"
diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs
index 664d2543f..f4d0751f7 100644
--- a/compiler/rustc_symbol_mangling/src/errors.rs
+++ b/compiler/rustc_symbol_mangling/src/errors.rs
@@ -1,11 +1,11 @@
//! Errors emitted by symbol_mangling.
use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
-use rustc_macros::SessionDiagnostic;
+use rustc_macros::Diagnostic;
use rustc_span::Span;
-#[derive(SessionDiagnostic)]
-#[diag(symbol_mangling::test_output)]
+#[derive(Diagnostic)]
+#[diag(symbol_mangling_test_output)]
pub struct TestOutput {
#[primary_span]
pub span: Span,
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index 9d89c9c52..150459ce0 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -26,19 +26,19 @@ pub fn report_symbol_names(tcx: TyCtxt<'_>) {
let crate_items = tcx.hir_crate_items(());
for id in crate_items.items() {
- symbol_names.process_attrs(id.def_id);
+ symbol_names.process_attrs(id.owner_id.def_id);
}
for id in crate_items.trait_items() {
- symbol_names.process_attrs(id.def_id);
+ symbol_names.process_attrs(id.owner_id.def_id);
}
for id in crate_items.impl_items() {
- symbol_names.process_attrs(id.def_id);
+ symbol_names.process_attrs(id.owner_id.def_id);
}
for id in crate_items.foreign_items() {
- symbol_names.process_attrs(id.def_id);
+ symbol_names.process_attrs(id.owner_id.def_id);
}
})
}
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 aa65a72ab..6aa031c83 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
@@ -540,7 +540,7 @@ fn encode_ty<'tcx>(
let mut s = String::new();
let def_id = adt_def.0.did;
if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() {
- // For for cross-language CFI support, the encoding must be compatible at the FFI
+ // For cross-language CFI support, the encoding must be compatible at the FFI
// boundary. For instance:
//
// struct type1 {};
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 79d0ef69b..ecfe6861e 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -7,10 +7,10 @@ use rustc_hir::def_id::{CrateNum, DefId};
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::print::{Print, Printer};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
use rustc_middle::ty::{
self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeVisitable, UintTy,
};
+use rustc_middle::ty::{GenericArg, GenericArgKind};
use rustc_span::symbol::kw;
use rustc_target::abi::Integer;
use rustc_target::spec::abi::Abi;
@@ -301,7 +301,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
// Encode impl generic params if the substitutions contain parameters (implying
// polymorphization is enabled) and this isn't an inherent impl.
- if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts()) {
+ if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_non_region_param()) {
self = self.path_generic_args(
|this| {
this.path_append_ns(
diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml
index 162376af4..fc37fdb1c 100644
--- a/compiler/rustc_target/Cargo.toml
+++ b/compiler/rustc_target/Cargo.toml
@@ -8,7 +8,8 @@ bitflags = "1.2.1"
tracing = "0.1"
serde_json = "1.0.59"
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" }
-rustc_index = { path = "../rustc_index" }
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index d2fb8c32f..9e5f0e4d1 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -47,7 +47,7 @@ pub enum PassMode {
/// Pass the argument indirectly via a hidden pointer.
/// The `extra_attrs` value, if any, is for the extra data (vtable or length)
/// which indicates that it refers to an unsized rvalue.
- /// `on_stack` defines that the the value should be passed at a fixed
+ /// `on_stack` defines that the value should be passed at a fixed
/// stack offset in accordance to the ABI rather than passed using a
/// pointer. This corresponds to the `byval` LLVM argument attribute.
Indirect { attrs: ArgAttributes, extra_attrs: Option<ArgAttributes>, on_stack: bool },
@@ -740,7 +740,8 @@ impl<'a, Ty> FnAbi<'a, Ty> {
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;
- // These are in alphabetical order, which is easy to maintain.
+ // tidy-alphabetical-start
static_assert_size!(ArgAbi<'_, usize>, 56);
static_assert_size!(FnAbi<'_, usize>, 80);
+ // tidy-alphabetical-end
}
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index ec334e588..7171ca7bf 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -1392,7 +1392,7 @@ pub struct PointeeInfo {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InitKind {
Zero,
- Uninit,
+ UninitMitigated0x01Fill,
}
/// Trait that needs to be implemented by the higher-level type representation
@@ -1498,72 +1498,4 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
Abi::Aggregate { sized } => sized && self.size.bytes() == 0,
}
}
-
- /// Determines if this type permits "raw" initialization by just transmuting some
- /// memory into an instance of `T`.
- ///
- /// `init_kind` indicates if the memory is zero-initialized or left uninitialized.
- ///
- /// This code is intentionally conservative, and will not detect
- /// * zero init of an enum whose 0 variant does not allow zero initialization
- /// * making uninitialized types who have a full valid range (ints, floats, raw pointers)
- /// * Any form of invalid value being made inside an array (unless the value is uninhabited)
- ///
- /// A strict form of these checks that uses const evaluation exists in
- /// `rustc_const_eval::might_permit_raw_init`, and a tracking issue for making these checks
- /// stricter is <https://github.com/rust-lang/rust/issues/66151>.
- ///
- /// FIXME: Once all the conservatism is removed from here, and the checks are ran by default,
- /// we can use the const evaluation checks always instead.
- pub fn might_permit_raw_init<C>(self, cx: &C, init_kind: InitKind) -> bool
- where
- Self: Copy,
- Ty: TyAbiInterface<'a, C>,
- C: HasDataLayout,
- {
- let scalar_allows_raw_init = move |s: Scalar| -> bool {
- match init_kind {
- InitKind::Zero => {
- // The range must contain 0.
- s.valid_range(cx).contains(0)
- }
- InitKind::Uninit => {
- // The range must include all values.
- s.is_always_valid(cx)
- }
- }
- };
-
- // Check the ABI.
- let valid = match self.abi {
- Abi::Uninhabited => false, // definitely UB
- Abi::Scalar(s) => scalar_allows_raw_init(s),
- Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2),
- Abi::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s),
- Abi::Aggregate { .. } => true, // Fields are checked below.
- };
- if !valid {
- // This is definitely not okay.
- return false;
- }
-
- // If we have not found an error yet, we need to recursively descend into fields.
- match &self.fields {
- FieldsShape::Primitive | FieldsShape::Union { .. } => {}
- FieldsShape::Array { .. } => {
- // FIXME(#66151): For now, we are conservative and do not check arrays by default.
- }
- FieldsShape::Arbitrary { offsets, .. } => {
- for idx in 0..offsets.len() {
- if !self.field(cx, idx).might_permit_raw_init(cx, init_kind) {
- // We found a field that is unhappy with this kind of initialization.
- return false;
- }
- }
- }
- }
-
- // FIXME(#66151): For now, we are conservative and do not check `self.variants`.
- true
- }
}
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index a7deab9d2..aaba0d7f0 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -11,7 +11,6 @@
#![feature(assert_matches)]
#![feature(associated_type_bounds)]
#![feature(exhaustive_patterns)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(rustc_attrs)]
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 1dad07a9a..2d2671549 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
@@ -1,11 +1,11 @@
use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{FramePointer, LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target, TargetOptions};
pub fn target() -> Target {
let llvm_target = "arm64-apple-ios14.0-macabi";
let mut base = opts("ios", Arch::Arm64_macabi);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-target", llvm_target]);
+ base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-target", llvm_target]);
Target {
llvm_target: llvm_target.into(),
diff --git a/compiler/rustc_target/src/spec/aarch64_nintendo_switch_freestanding.rs b/compiler/rustc_target/src/spec/aarch64_nintendo_switch_freestanding.rs
index b301ce68a..529e98d2c 100644
--- a/compiler/rustc_target/src/spec/aarch64_nintendo_switch_freestanding.rs
+++ b/compiler/rustc_target/src/spec/aarch64_nintendo_switch_freestanding.rs
@@ -1,4 +1,4 @@
-use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelroLevel, Target, TargetOptions};
+use super::{Cc, LinkerFlavor, Lld, PanicStrategy, RelroLevel, Target, TargetOptions};
const LINKER_SCRIPT: &str = include_str!("./aarch64_nintendo_switch_freestanding_linker_script.ld");
@@ -10,7 +10,7 @@ pub fn target() -> Target {
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
arch: "aarch64".into(),
options: TargetOptions {
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
link_script: Some(LINKER_SCRIPT.into()),
os: "horizon".into(),
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
index d3fd7051a..4ae6d4120 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
@@ -6,11 +6,11 @@
//
// For example, `-C target-cpu=cortex-a53`.
-use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
+use super::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
let opts = TargetOptions {
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
features: "+strict-align,+neon,+fp-armv8".into(),
relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
index 6316abe1b..2385cb69a 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
@@ -6,12 +6,12 @@
//
// For example, `-C target-cpu=cortex-a53`.
-use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
+use super::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
let opts = TargetOptions {
abi: "softfloat".into(),
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
features: "+strict-align,-neon,-fp-armv8".into(),
relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs b/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs
index 3ef04c676..817ff2422 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs
@@ -2,13 +2,13 @@
// uefi-base module for generic UEFI options.
use super::uefi_msvc_base;
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, Lld, Target};
pub fn target() -> Target {
let mut base = uefi_msvc_base::opts();
base.max_atomic_width = Some(128);
- base.add_pre_link_args(LinkerFlavor::Msvc, &["/machine:arm64"]);
+ base.add_pre_link_args(LinkerFlavor::Msvc(Lld::No), &["/machine:arm64"]);
Target {
llvm_target: "aarch64-unknown-windows".into(),
diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs
index 337554dc9..ce45fa139 100644
--- a/compiler/rustc_target/src/spec/abi.rs
+++ b/compiler/rustc_target/src/spec/abi.rs
@@ -1,6 +1,8 @@
use std::fmt;
use rustc_macros::HashStable_Generic;
+use rustc_span::symbol::sym;
+use rustc_span::{Span, Symbol};
#[cfg(test)]
mod tests;
@@ -94,6 +96,142 @@ pub fn all_names() -> Vec<&'static str> {
AbiDatas.iter().map(|d| d.name).collect()
}
+pub fn enabled_names(features: &rustc_feature::Features, span: Span) -> Vec<&'static str> {
+ AbiDatas
+ .iter()
+ .map(|d| d.name)
+ .filter(|name| is_enabled(features, span, name).is_ok())
+ .collect()
+}
+
+pub enum AbiDisabled {
+ Unstable { feature: Symbol, explain: &'static str },
+ Unrecognized,
+}
+
+pub fn is_enabled(
+ features: &rustc_feature::Features,
+ span: Span,
+ name: &str,
+) -> Result<(), AbiDisabled> {
+ let s = is_stable(name);
+ if let Err(AbiDisabled::Unstable { feature, .. }) = s {
+ if features.enabled(feature) || span.allows_unstable(feature) {
+ return Ok(());
+ }
+ }
+ s
+}
+
+pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
+ match name {
+ // Stable
+ "Rust" | "C" | "cdecl" | "stdcall" | "fastcall" | "aapcs" | "win64" | "sysv64"
+ | "system" => Ok(()),
+ "rust-intrinsic" => Err(AbiDisabled::Unstable {
+ feature: sym::intrinsics,
+ explain: "intrinsics are subject to change",
+ }),
+ "platform-intrinsic" => Err(AbiDisabled::Unstable {
+ feature: sym::platform_intrinsics,
+ explain: "platform intrinsics are experimental and possibly buggy",
+ }),
+ "vectorcall" => Err(AbiDisabled::Unstable {
+ feature: sym::abi_vectorcall,
+ explain: "vectorcall is experimental and subject to change",
+ }),
+ "thiscall" => Err(AbiDisabled::Unstable {
+ feature: sym::abi_thiscall,
+ explain: "thiscall is experimental and subject to change",
+ }),
+ "rust-call" => Err(AbiDisabled::Unstable {
+ feature: sym::unboxed_closures,
+ explain: "rust-call ABI is subject to change",
+ }),
+ "rust-cold" => Err(AbiDisabled::Unstable {
+ feature: sym::rust_cold_cc,
+ explain: "rust-cold is experimental and subject to change",
+ }),
+ "ptx-kernel" => Err(AbiDisabled::Unstable {
+ feature: sym::abi_ptx,
+ explain: "PTX ABIs are experimental and subject to change",
+ }),
+ "unadjusted" => Err(AbiDisabled::Unstable {
+ feature: sym::abi_unadjusted,
+ explain: "unadjusted ABI is an implementation detail and perma-unstable",
+ }),
+ "msp430-interrupt" => Err(AbiDisabled::Unstable {
+ feature: sym::abi_msp430_interrupt,
+ explain: "msp430-interrupt ABI is experimental and subject to change",
+ }),
+ "x86-interrupt" => Err(AbiDisabled::Unstable {
+ feature: sym::abi_x86_interrupt,
+ explain: "x86-interrupt ABI is experimental and subject to change",
+ }),
+ "amdgpu-kernel" => Err(AbiDisabled::Unstable {
+ feature: sym::abi_amdgpu_kernel,
+ explain: "amdgpu-kernel ABI is experimental and subject to change",
+ }),
+ "avr-interrupt" | "avr-non-blocking-interrupt" => Err(AbiDisabled::Unstable {
+ feature: sym::abi_avr_interrupt,
+ explain: "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change",
+ }),
+ "efiapi" => Err(AbiDisabled::Unstable {
+ feature: sym::abi_efiapi,
+ explain: "efiapi ABI is experimental and subject to change",
+ }),
+ "C-cmse-nonsecure-call" => Err(AbiDisabled::Unstable {
+ 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",
+ }),
+ _ => Err(AbiDisabled::Unrecognized),
+ }
+}
+
impl Abi {
/// Default ABI chosen for `extern fn` declarations without an explicit ABI.
pub const FALLBACK: Abi = Abi::C { unwind: false };
diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs
index 9f3e0bd5e..9c1df1a06 100644
--- a/compiler/rustc_target/src/spec/android_base.rs
+++ b/compiler/rustc_target/src/spec/android_base.rs
@@ -1,10 +1,12 @@
-use crate::spec::TargetOptions;
+use crate::spec::{SanitizerSet, TargetOptions};
pub fn opts() -> TargetOptions {
let mut base = super::linux_base::opts();
base.os = "android".into();
+ base.is_like_android = true;
base.default_dwarf_version = 2;
base.has_thread_local = false;
+ base.supported_sanitizers = SanitizerSet::ADDRESS;
// This is for backward compatibility, see https://github.com/rust-lang/rust/issues/49867
// for context. (At that time, there was no `-C force-unwind-tables`, so the only solution
// was to always emit `uwtable`).
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 2c72bf88a..40bc59ca1 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, DebuginfoKind, FramePointer, SplitDebuginfo, StaticCow, TargetOptions};
-use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor};
+use crate::spec::{cvs, Cc, DebuginfoKind, FramePointer, LinkArgs};
+use crate::spec::{LinkerFlavor, Lld, SplitDebuginfo, StaticCow, TargetOptions};
fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> LinkArgs {
let platform_name: StaticCow<str> = match abi {
@@ -20,17 +20,16 @@ fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> Lin
.into();
let mut args = TargetOptions::link_args(
- LinkerFlavor::Lld(LldFlavor::Ld64),
+ LinkerFlavor::Darwin(Cc::No, Lld::No),
&["-arch", arch, "-platform_version"],
);
- // Manually add owned args unsupported by link arg building helpers.
- args.entry(LinkerFlavor::Lld(LldFlavor::Ld64)).or_default().extend([
- platform_name,
- platform_version.clone(),
- platform_version,
- ]);
+ super::add_link_args_iter(
+ &mut args,
+ LinkerFlavor::Darwin(Cc::No, Lld::No),
+ [platform_name, platform_version.clone(), platform_version].into_iter(),
+ );
if abi != "macabi" {
- super::add_link_args(&mut args, LinkerFlavor::Gcc, &["-arch", arch]);
+ super::add_link_args(&mut args, LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-arch", arch]);
}
args
@@ -55,11 +54,11 @@ pub fn opts(os: &'static str, arch: &'static str, abi: &'static str) -> TargetOp
TargetOptions {
os: os.into(),
vendor: "apple".into(),
+ linker_flavor: LinkerFlavor::Darwin(Cc::Yes, Lld::No),
// macOS has -dead_strip, which doesn't rely on function_sections
function_sections: false,
dynamic_linking: true,
pre_link_args: pre_link_args(os, arch, abi),
- linker_is_gnu: false,
families: cvs!["unix"],
is_like_osx: true,
default_dwarf_version: 2,
@@ -71,7 +70,6 @@ pub fn opts(os: &'static str, arch: &'static str, abi: &'static str) -> TargetOp
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
eh_frame_header: false,
- lld_flavor: LldFlavor::Ld64,
debuginfo_kind: DebuginfoKind::DwarfDsym,
// The historical default for macOS targets is to run `dsymutil` which
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
index 511693abe..8c65d6afc 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
@@ -1,8 +1,7 @@
// Targets the Big endian Cortex-R4/R5 processor (ARMv7-R)
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -13,7 +12,7 @@ pub fn target() -> Target {
options: TargetOptions {
abi: "eabi".into(),
endian: Endian::Big,
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
relocation_model: RelocModel::Static,
panic_strategy: PanicStrategy::Abort,
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
index 5df4a0a15..7013bc60d 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
@@ -1,8 +1,7 @@
// Targets the Cortex-R4F/R5F processor (ARMv7-R)
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -13,7 +12,7 @@ pub fn target() -> Target {
options: TargetOptions {
abi: "eabihf".into(),
endian: Endian::Big,
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
relocation_model: RelocModel::Static,
panic_strategy: PanicStrategy::Abort,
diff --git a/compiler/rustc_target/src/spec/armv4t_none_eabi.rs b/compiler/rustc_target/src/spec/armv4t_none_eabi.rs
index 797dfe52b..7ac1aab3b 100644
--- a/compiler/rustc_target/src/spec/armv4t_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv4t_none_eabi.rs
@@ -16,7 +16,7 @@
//! The default link script is very likely wrong, so you should use
//! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.
-use crate::spec::{cvs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{cvs, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -35,7 +35,7 @@ pub fn target() -> Target {
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
options: TargetOptions {
abi: "eabi".into(),
- linker_flavor: LinkerFlavor::Ld,
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::No),
linker: Some("arm-none-eabi-ld".into()),
asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",],
// Force-enable 32-bit atomics, which allows the use of atomic load/store only.
diff --git a/compiler/rustc_target/src/spec/armv5te_none_eabi.rs b/compiler/rustc_target/src/spec/armv5te_none_eabi.rs
new file mode 100644
index 000000000..dfd27b654
--- /dev/null
+++ b/compiler/rustc_target/src/spec/armv5te_none_eabi.rs
@@ -0,0 +1,41 @@
+//! Targets the ARMv5TE, with code as `a32` code by default.
+
+use crate::spec::{cvs, FramePointer, Target, TargetOptions};
+
+pub fn target() -> Target {
+ Target {
+ llvm_target: "armv5te-none-eabi".into(),
+ pointer_width: 32,
+ arch: "arm".into(),
+ /* Data layout args are '-' separated:
+ * little endian
+ * stack is 64-bit aligned (EABI)
+ * pointers are 32-bit
+ * i64 must be 64-bit aligned (EABI)
+ * mangle names with ELF style
+ * native integers are 32-bit
+ * All other elements are default
+ */
+ data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
+
+ options: TargetOptions {
+ abi: "eabi".into(),
+ // extra args passed to the external assembler (assuming `arm-none-eabi-as`):
+ // * activate t32/a32 interworking
+ // * use arch ARMv5TE
+ // * use little-endian
+ asm_args: cvs!["-mthumb-interwork", "-march=armv5te", "-mlittle-endian",],
+ // minimum extra features, these cannot be disabled via -C
+ // Also force-enable 32-bit atomics, which allows the use of atomic load/store only.
+ // The resulting atomics are ABI incompatible with atomics backed by libatomic.
+ features: "+soft-float,+strict-align,+atomics-32".into(),
+ frame_pointer: FramePointer::MayOmit,
+ main_needs_argc_argv: false,
+ // don't have atomic compare-and-swap
+ atomic_cas: false,
+ has_thumb_interworking: true,
+
+ ..super::thumb_base::opts()
+ },
+ }
+}
diff --git a/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs b/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs
index 1bba39393..40ec6f961 100644
--- a/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs
+++ b/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs
@@ -1,4 +1,4 @@
-use crate::spec::{cvs, LinkerFlavor, RelocModel, Target, TargetOptions};
+use crate::spec::{cvs, Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions};
/// A base target for Nintendo 3DS devices using the devkitARM toolchain.
///
@@ -6,7 +6,7 @@ use crate::spec::{cvs, LinkerFlavor, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
let pre_link_args = TargetOptions::link_args(
- LinkerFlavor::Gcc,
+ LinkerFlavor::Gnu(Cc::Yes, Lld::No),
&["-specs=3dsx.specs", "-mtune=mpcore", "-mfloat-abi=hard", "-mtp=soft"],
);
@@ -21,7 +21,6 @@ pub fn target() -> Target {
env: "newlib".into(),
vendor: "nintendo".into(),
abi: "eabihf".into(),
- linker_flavor: LinkerFlavor::Gcc,
cpu: "mpcore".into(),
families: cvs!["unix"],
linker: Some("arm-none-eabi-gcc".into()),
diff --git a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
index 38c117a49..402e0fd92 100644
--- a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, SanitizerSet, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, Target, TargetOptions};
// This target if is for the baseline of the Android v7a ABI
// in thumb mode. It's named armv7-* instead of thumbv7-*
@@ -10,7 +10,7 @@ use crate::spec::{LinkerFlavor, SanitizerSet, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::android_base::opts();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-march=armv7-a"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-march=armv7-a"]);
Target {
llvm_target: "armv7-none-linux-android".into(),
pointer_width: 32,
diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
index cb5cbe158..4e20fb325 100644
--- a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
@@ -14,12 +14,12 @@
// - `relocation-model` set to `static`; also no PIE, no relro and no dynamic
// linking. rationale: matches `thumb` targets
-use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
+use super::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
let opts = TargetOptions {
abi: "eabi".into(),
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
features: "+v7,+thumb2,+soft-float,-neon,+strict-align".into(),
relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
index fb5dd2e75..ae70129ae 100644
--- a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
@@ -5,12 +5,12 @@
// changes (list in `armv7a_none_eabi.rs`) to bring it closer to the bare-metal
// `thumb` & `aarch64` targets.
-use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
+use super::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
let opts = TargetOptions {
abi: "eabihf".into(),
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
features: "+v7,+vfp3,-d32,+thumb2,-neon,+strict-align".into(),
relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
index 5f1da09b3..25f301ccc 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
@@ -1,7 +1,6 @@
// Targets the Little-endian Cortex-R4/R5 processor (ARMv7-R)
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -12,7 +11,7 @@ pub fn target() -> Target {
options: TargetOptions {
abi: "eabi".into(),
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
relocation_model: RelocModel::Static,
panic_strategy: PanicStrategy::Abort,
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
index 0038ed0df..40449759d 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
@@ -1,7 +1,6 @@
// Targets the Little-endian Cortex-R4F/R5F processor (ARMv7-R)
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -12,7 +11,7 @@ pub fn target() -> Target {
options: TargetOptions {
abi: "eabihf".into(),
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
relocation_model: RelocModel::Static,
panic_strategy: PanicStrategy::Abort,
diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs
index 8cca33cc4..9c3406b53 100644
--- a/compiler/rustc_target/src/spec/avr_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, RelocModel, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions};
/// A base target for AVR devices using the GNU toolchain.
///
@@ -17,8 +17,11 @@ pub fn target(target_cpu: &'static str, mmcu: &'static str) -> Target {
linker: Some("avr-gcc".into()),
eh_frame_header: false,
- pre_link_args: TargetOptions::link_args(LinkerFlavor::Gcc, &[mmcu]),
- late_link_args: TargetOptions::link_args(LinkerFlavor::Gcc, &["-lgcc"]),
+ pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[mmcu]),
+ late_link_args: TargetOptions::link_args(
+ LinkerFlavor::Gnu(Cc::Yes, Lld::No),
+ &["-lgcc"],
+ ),
max_atomic_width: Some(0),
atomic_cas: false,
relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs
index 962ad0c66..4c2775850 100644
--- a/compiler/rustc_target/src/spec/fuchsia_base.rs
+++ b/compiler/rustc_target/src/spec/fuchsia_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::{crt_objects, cvs, LinkOutputKind, LinkerFlavor, LldFlavor, TargetOptions};
+use crate::spec::{crt_objects, cvs, Cc, LinkOutputKind, LinkerFlavor, Lld, TargetOptions};
pub fn opts() -> TargetOptions {
// This mirrors the linker options provided by clang. We presume lld for
@@ -7,7 +7,7 @@ pub fn opts() -> TargetOptions {
//
// https://github.com/llvm/llvm-project/blob/db9322b2066c55254e7691efeab863f43bfcc084/clang/lib/Driver/ToolChains/Fuchsia.cpp#L31
let pre_link_args = TargetOptions::link_args(
- LinkerFlavor::Ld,
+ LinkerFlavor::Gnu(Cc::No, Lld::No),
&[
"--build-id",
"--hash-style=gnu",
@@ -25,7 +25,7 @@ pub fn opts() -> TargetOptions {
TargetOptions {
os: "fuchsia".into(),
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
dynamic_linking: true,
families: cvs!["unix"],
diff --git a/compiler/rustc_target/src/spec/hermit_base.rs b/compiler/rustc_target/src/spec/hermit_base.rs
index 562ccef7e..dd9991381 100644
--- a/compiler/rustc_target/src/spec/hermit_base.rs
+++ b/compiler/rustc_target/src/spec/hermit_base.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions, TlsModel};
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, TargetOptions, TlsModel};
pub fn opts() -> TargetOptions {
let pre_link_args = TargetOptions::link_args(
- LinkerFlavor::Ld,
+ LinkerFlavor::Gnu(Cc::No, Lld::No),
&["--build-id", "--hash-style=gnu", "--Bstatic"],
);
TargetOptions {
os: "hermit".into(),
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
has_thread_local: true,
pre_link_args,
diff --git a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
index 2a24e4459..3aad05eb2 100644
--- a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
@@ -1,4 +1,4 @@
-use crate::spec::Target;
+use crate::spec::{Cc, LinkerFlavor, Target};
pub fn target() -> Target {
let mut base = super::linux_musl_base::opts();
@@ -9,7 +9,7 @@ pub fn target() -> Target {
base.crt_static_default = false;
base.has_rpath = true;
- base.linker_is_gnu = false;
+ base.linker_flavor = LinkerFlavor::Unix(Cc::Yes);
base.c_enum_min_bits = 8;
diff --git a/compiler/rustc_target/src/spec/i386_apple_ios.rs b/compiler/rustc_target/src/spec/i386_apple_ios.rs
index 8b6266c58..b85214a9c 100644
--- a/compiler/rustc_target/src/spec/i386_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/i386_apple_ios.rs
@@ -14,8 +14,7 @@ pub fn target() -> Target {
arch: "x86".into(),
options: TargetOptions {
max_atomic_width: Some(64),
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- stack_probes: StackProbeType::Call,
+ stack_probes: StackProbeType::X86,
..base
},
}
diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
index 5e9ceb844..15607c12e 100644
--- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
@@ -1,14 +1,13 @@
-use crate::spec::{FramePointer, LinkerFlavor, StackProbeType, Target, TargetOptions};
+use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
// ld64 only understand i386 and not i686
let mut base = super::apple_base::opts("macos", "i386", "");
base.cpu = "yonah".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]);
+ base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m32"]);
base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove());
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.stack_probes = StackProbeType::X86;
base.frame_pointer = FramePointer::Always;
// Clang automatically chooses a more specific target based on
diff --git a/compiler/rustc_target/src/spec/i686_linux_android.rs b/compiler/rustc_target/src/spec/i686_linux_android.rs
index bdaf5c990..c7c30c239 100644
--- a/compiler/rustc_target/src/spec/i686_linux_android.rs
+++ b/compiler/rustc_target/src/spec/i686_linux_android.rs
@@ -11,8 +11,7 @@ pub fn target() -> Target {
// https://developer.android.com/ndk/guides/abis.html#x86
base.cpu = "pentiumpro".into();
base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".into();
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.stack_probes = StackProbeType::X86;
Target {
llvm_target: "i686-linux-android".into(),
diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
index 631865439..7a1113875 100644
--- a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{FramePointer, LinkerFlavor, Target};
+use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target};
pub fn target() -> Target {
let mut base = super::windows_gnu_base::opts();
@@ -9,8 +9,11 @@ pub fn target() -> Target {
// Mark all dynamic libraries and executables as compatible with the larger 4GiB address
// space available to x86 Windows binaries on x86_64.
- base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pe", "--large-address-aware"]);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-Wl,--large-address-aware"]);
+ base.add_pre_link_args(
+ LinkerFlavor::Gnu(Cc::No, Lld::No),
+ &["-m", "i386pe", "--large-address-aware"],
+ );
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-Wl,--large-address-aware"]);
Target {
llvm_target: "i686-pc-windows-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs
index f4ceaa1ca..db4c00dc6 100644
--- a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, Lld, Target};
pub fn target() -> Target {
let mut base = super::windows_msvc_base::opts();
@@ -6,7 +6,7 @@ pub fn target() -> Target {
base.max_atomic_width = Some(64);
base.add_pre_link_args(
- LinkerFlavor::Msvc,
+ LinkerFlavor::Msvc(Lld::No),
&[
// Mark all dynamic libraries and executables as compatible with the larger 4GiB address
// space available to x86 Windows binaries on x86_64.
diff --git a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
index aff284bf2..35ca78034 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
@@ -1,12 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::freebsd_base::opts();
base.cpu = "pentium4".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "-Wl,-znotext"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32", "-Wl,-znotext"]);
+ base.stack_probes = StackProbeType::X86;
Target {
llvm_target: "i686-unknown-freebsd".into(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
index 87aa74e40..e6b72336c 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
@@ -1,12 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::haiku_base::opts();
base.cpu = "pentium4".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]);
+ base.stack_probes = StackProbeType::X86;
Target {
llvm_target: "i686-unknown-haiku".into(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
index 765803d16..73e536a7e 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
@@ -1,12 +1,12 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts();
base.cpu = "pentium4".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.supported_sanitizers = SanitizerSet::ADDRESS;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]);
+ base.stack_probes = StackProbeType::X86;
Target {
llvm_target: "i686-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
index d94928043..3825082ba 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
@@ -1,12 +1,11 @@
-use crate::spec::{FramePointer, LinkerFlavor, StackProbeType, Target};
+use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::linux_musl_base::opts();
base.cpu = "pentium4".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "-Wl,-melf_i386"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32", "-Wl,-melf_i386"]);
+ base.stack_probes = StackProbeType::X86;
// The unwinder used by i686-unknown-linux-musl, the LLVM libunwind
// implementation, apparently relies on frame pointers existing... somehow.
diff --git a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
index 8de698b51..b191996c7 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
@@ -1,12 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::netbsd_base::opts();
base.cpu = "pentium4".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]);
+ base.stack_probes = StackProbeType::X86;
Target {
llvm_target: "i686-unknown-netbsdelf".into(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
index 7f25a1a16..8babe5597 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
@@ -1,12 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::openbsd_base::opts();
base.cpu = "pentium4".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "-fuse-ld=lld"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32", "-fuse-ld=lld"]);
+ base.stack_probes = StackProbeType::X86;
Target {
llvm_target: "i686-unknown-openbsd".into(),
diff --git a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
index d52810d2f..a3e325698 100644
--- a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{FramePointer, LinkerFlavor, Target};
+use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target};
pub fn target() -> Target {
let mut base = super::windows_uwp_gnu_base::opts();
@@ -8,8 +8,11 @@ pub fn target() -> Target {
// Mark all dynamic libraries and executables as compatible with the larger 4GiB address
// space available to x86 Windows binaries on x86_64.
- base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pe", "--large-address-aware"]);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-Wl,--large-address-aware"]);
+ base.add_pre_link_args(
+ LinkerFlavor::Gnu(Cc::No, Lld::No),
+ &["-m", "i386pe", "--large-address-aware"],
+ );
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-Wl,--large-address-aware"]);
Target {
llvm_target: "i686-pc-windows-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
index f62404e82..b5cfdfceb 100644
--- a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
@@ -1,12 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::vxworks_base::opts();
base.cpu = "pentium4".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]);
+ base.stack_probes = StackProbeType::X86;
Target {
llvm_target: "i686-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/illumos_base.rs b/compiler/rustc_target/src/spec/illumos_base.rs
index 77e000474..8ac351584 100644
--- a/compiler/rustc_target/src/spec/illumos_base.rs
+++ b/compiler/rustc_target/src/spec/illumos_base.rs
@@ -1,8 +1,8 @@
-use crate::spec::{cvs, FramePointer, LinkerFlavor, TargetOptions};
+use crate::spec::{cvs, Cc, FramePointer, LinkerFlavor, TargetOptions};
pub fn opts() -> TargetOptions {
let late_link_args = TargetOptions::link_args(
- LinkerFlavor::Gcc,
+ LinkerFlavor::Unix(Cc::Yes),
&[
// The illumos libc contains a stack unwinding implementation, as
// does libgcc_s. The latter implementation includes several
@@ -30,7 +30,7 @@ pub fn opts() -> TargetOptions {
has_rpath: true,
families: cvs!["unix"],
is_like_solaris: true,
- linker_is_gnu: false,
+ linker_flavor: LinkerFlavor::Unix(Cc::Yes),
limit_rdylib_exports: false, // Linker doesn't support this
frame_pointer: FramePointer::Always,
eh_frame_header: false,
diff --git a/compiler/rustc_target/src/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs
index b7bc1072b..3a4d83fad 100644
--- a/compiler/rustc_target/src/spec/l4re_base.rs
+++ b/compiler/rustc_target/src/spec/l4re_base.rs
@@ -1,13 +1,12 @@
-use crate::spec::{cvs, LinkerFlavor, PanicStrategy, RelocModel, TargetOptions};
+use crate::spec::{cvs, Cc, LinkerFlavor, PanicStrategy, RelocModel, TargetOptions};
pub fn opts() -> TargetOptions {
TargetOptions {
os: "l4re".into(),
env: "uclibc".into(),
- linker_flavor: LinkerFlavor::Ld,
+ linker_flavor: LinkerFlavor::Unix(Cc::No),
panic_strategy: PanicStrategy::Abort,
linker: Some("l4-bender".into()),
- linker_is_gnu: false,
families: cvs!["unix"],
relocation_model: RelocModel::Static,
..Default::default()
diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs
index 0f5d85205..f41533a95 100644
--- a/compiler/rustc_target/src/spec/linux_kernel_base.rs
+++ b/compiler/rustc_target/src/spec/linux_kernel_base.rs
@@ -6,8 +6,7 @@ pub fn opts() -> TargetOptions {
env: "gnu".into(),
disable_redzone: true,
panic_strategy: PanicStrategy::Abort,
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- stack_probes: StackProbeType::Call,
+ stack_probes: StackProbeType::X86,
frame_pointer: FramePointer::Always,
position_independent_executables: true,
needs_plt: true,
diff --git a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
index cfc8ec21c..75beb91b1 100644
--- a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
+++ b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
@@ -1,11 +1,13 @@
-use crate::spec::{cvs, Target, TargetOptions};
-use crate::spec::{LinkerFlavor, LldFlavor, RelocModel};
+use crate::spec::{cvs, Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions};
// The PSP has custom linker requirements.
const LINKER_SCRIPT: &str = include_str!("./mipsel_sony_psp_linker_script.ld");
pub fn target() -> Target {
- let pre_link_args = TargetOptions::link_args(LinkerFlavor::Ld, &["--emit-relocs", "--nmagic"]);
+ let pre_link_args = TargetOptions::link_args(
+ LinkerFlavor::Gnu(Cc::No, Lld::No),
+ &["--emit-relocs", "--nmagic"],
+ );
Target {
llvm_target: "mipsel-sony-psp".into(),
@@ -16,7 +18,7 @@ pub fn target() -> Target {
options: TargetOptions {
os: "psp".into(),
vendor: "sony".into(),
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
cpu: "mips2".into(),
linker: Some("rust-lld".into()),
relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_none.rs b/compiler/rustc_target/src/spec/mipsel_unknown_none.rs
index fe2aa2de8..43b01e7a0 100644
--- a/compiler/rustc_target/src/spec/mipsel_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/mipsel_unknown_none.rs
@@ -2,8 +2,7 @@
//!
//! Can be used for MIPS M4K core (e.g. on PIC32MX devices)
-use crate::spec::{LinkerFlavor, LldFlavor, RelocModel};
-use crate::spec::{PanicStrategy, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -13,7 +12,7 @@ pub fn target() -> Target {
arch: "mips".into(),
options: TargetOptions {
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
cpu: "mips32r2".into(),
features: "+mips32r2,+soft-float,+noabicalls".into(),
max_atomic_width: Some(32),
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index dc16739bd..8909cf33a 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -90,17 +90,73 @@ mod windows_msvc_base;
mod windows_uwp_gnu_base;
mod windows_uwp_msvc_base;
+/// Linker is called through a C/C++ compiler.
+#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
+pub enum Cc {
+ Yes,
+ No,
+}
+
+/// Linker is LLD.
+#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
+pub enum Lld {
+ Yes,
+ No,
+}
+
+/// All linkers have some kinds of command line interfaces and rustc needs to know which commands
+/// to use with each of them. So we cluster all such interfaces into a (somewhat arbitrary) number
+/// of classes that we call "linker flavors".
+///
+/// Technically, it's not even necessary, we can nearly always infer the flavor from linker name
+/// and target properties like `is_like_windows`/`is_like_osx`/etc. However, the PRs originally
+/// introducing `-Clinker-flavor` (#40018 and friends) were aiming to reduce this kind of inference
+/// and provide something certain and explicitly specified instead, and that design goal is still
+/// relevant now.
+///
+/// The second goal is to keep the number of flavors to the minimum if possible.
+/// LLD somewhat forces our hand here because that linker is self-sufficent only if its executable
+/// (`argv[0]`) is named in specific way, otherwise it doesn't work and requires a
+/// `-flavor LLD_FLAVOR` argument to choose which logic to use. Our shipped `rust-lld` in
+/// particular is not named in such specific way, so it needs the flavor option, so we make our
+/// linker flavors sufficiently fine-grained to satisfy LLD without inferring its flavor from other
+/// target properties, in accordance with the first design goal.
+///
+/// The first component of the flavor is tightly coupled with the compilation target,
+/// while the `Cc` and `Lld` flags can vary withing the same target.
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum LinkerFlavor {
- Gcc,
- Ld,
- Lld(LldFlavor),
- Msvc,
+ /// Unix-like linker with GNU extensions (both naked and compiler-wrapped forms).
+ /// Besides similar "default" Linux/BSD linkers this also includes Windows/GNU linker,
+ /// which is somewhat different because it doesn't produce ELFs.
+ Gnu(Cc, Lld),
+ /// Unix-like linker for Apple targets (both naked and compiler-wrapped forms).
+ /// Extracted from the "umbrella" `Unix` flavor due to its corresponding LLD flavor.
+ Darwin(Cc, Lld),
+ /// Unix-like linker for Wasm targets (both naked and compiler-wrapped forms).
+ /// Extracted from the "umbrella" `Unix` flavor due to its corresponding LLD flavor.
+ /// Non-LLD version does not exist, so the lld flag is currently hardcoded here.
+ WasmLld(Cc),
+ /// Basic Unix-like linker for "any other Unix" targets (Solaris/illumos, L4Re, MSP430, etc),
+ /// possibly with non-GNU extensions (both naked and compiler-wrapped forms).
+ /// LLD doesn't support any of these.
+ Unix(Cc),
+ /// MSVC-style linker for Windows and UEFI, LLD supports it.
+ Msvc(Lld),
+ /// Emscripten Compiler Frontend, a wrapper around `WasmLld(Cc::Yes)` that has a different
+ /// interface and produces some additional JavaScript output.
EmCc,
+ // Below: other linker-like tools with unique interfaces for exotic targets.
+ /// Linker tool for BPF.
Bpf,
+ /// Linker tool for Nvidia PTX.
Ptx,
}
+/// Linker flavors available externally through command line (`-Clinker-flavor`)
+/// or json target specifications.
+/// FIXME: This set has accumulated historically, bring it more in line with the internal
+/// linker flavors (`LinkerFlavor`).
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum LinkerFlavorCli {
Gcc,
@@ -148,12 +204,32 @@ impl ToJson for LldFlavor {
}
impl LinkerFlavor {
- pub fn from_cli(cli: LinkerFlavorCli) -> LinkerFlavor {
+ pub fn from_cli(cli: LinkerFlavorCli, target: &TargetOptions) -> LinkerFlavor {
+ Self::from_cli_impl(cli, target.linker_flavor.lld_flavor(), target.linker_flavor.is_gnu())
+ }
+
+ /// The passed CLI flavor is preferred over other args coming from the default target spec,
+ /// so this function can produce a flavor that is incompatible with the current target.
+ /// FIXME: Produce errors when `-Clinker-flavor` is set to something incompatible
+ /// with the current target.
+ fn from_cli_impl(cli: LinkerFlavorCli, lld_flavor: LldFlavor, is_gnu: bool) -> LinkerFlavor {
match cli {
- LinkerFlavorCli::Gcc => LinkerFlavor::Gcc,
- LinkerFlavorCli::Ld => LinkerFlavor::Ld,
- LinkerFlavorCli::Lld(lld_flavor) => LinkerFlavor::Lld(lld_flavor),
- LinkerFlavorCli::Msvc => LinkerFlavor::Msvc,
+ LinkerFlavorCli::Gcc => match lld_flavor {
+ LldFlavor::Ld if is_gnu => LinkerFlavor::Gnu(Cc::Yes, Lld::No),
+ LldFlavor::Ld64 => LinkerFlavor::Darwin(Cc::Yes, Lld::No),
+ LldFlavor::Wasm => LinkerFlavor::WasmLld(Cc::Yes),
+ LldFlavor::Ld | LldFlavor::Link => LinkerFlavor::Unix(Cc::Yes),
+ },
+ LinkerFlavorCli::Ld => match lld_flavor {
+ LldFlavor::Ld if is_gnu => LinkerFlavor::Gnu(Cc::No, Lld::No),
+ LldFlavor::Ld64 => LinkerFlavor::Darwin(Cc::No, Lld::No),
+ LldFlavor::Ld | LldFlavor::Wasm | LldFlavor::Link => LinkerFlavor::Unix(Cc::No),
+ },
+ LinkerFlavorCli::Lld(LldFlavor::Ld) => LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+ LinkerFlavorCli::Lld(LldFlavor::Ld64) => LinkerFlavor::Darwin(Cc::No, Lld::Yes),
+ LinkerFlavorCli::Lld(LldFlavor::Wasm) => LinkerFlavor::WasmLld(Cc::No),
+ LinkerFlavorCli::Lld(LldFlavor::Link) => LinkerFlavor::Msvc(Lld::Yes),
+ LinkerFlavorCli::Msvc => LinkerFlavor::Msvc(Lld::No),
LinkerFlavorCli::Em => LinkerFlavor::EmCc,
LinkerFlavorCli::BpfLinker => LinkerFlavor::Bpf,
LinkerFlavorCli::PtxLinker => LinkerFlavor::Ptx,
@@ -162,15 +238,40 @@ impl LinkerFlavor {
fn to_cli(self) -> LinkerFlavorCli {
match self {
- LinkerFlavor::Gcc => LinkerFlavorCli::Gcc,
- LinkerFlavor::Ld => LinkerFlavorCli::Ld,
- LinkerFlavor::Lld(lld_flavor) => LinkerFlavorCli::Lld(lld_flavor),
- LinkerFlavor::Msvc => LinkerFlavorCli::Msvc,
+ LinkerFlavor::Gnu(Cc::Yes, _)
+ | LinkerFlavor::Darwin(Cc::Yes, _)
+ | LinkerFlavor::WasmLld(Cc::Yes)
+ | LinkerFlavor::Unix(Cc::Yes) => LinkerFlavorCli::Gcc,
+ LinkerFlavor::Gnu(_, Lld::Yes) => LinkerFlavorCli::Lld(LldFlavor::Ld),
+ LinkerFlavor::Darwin(_, Lld::Yes) => LinkerFlavorCli::Lld(LldFlavor::Ld64),
+ LinkerFlavor::WasmLld(..) => LinkerFlavorCli::Lld(LldFlavor::Wasm),
+ LinkerFlavor::Gnu(..) | LinkerFlavor::Darwin(..) | LinkerFlavor::Unix(..) => {
+ LinkerFlavorCli::Ld
+ }
+ LinkerFlavor::Msvc(Lld::Yes) => LinkerFlavorCli::Lld(LldFlavor::Link),
+ LinkerFlavor::Msvc(..) => LinkerFlavorCli::Msvc,
LinkerFlavor::EmCc => LinkerFlavorCli::Em,
LinkerFlavor::Bpf => LinkerFlavorCli::BpfLinker,
LinkerFlavor::Ptx => LinkerFlavorCli::PtxLinker,
}
}
+
+ pub fn lld_flavor(self) -> LldFlavor {
+ match self {
+ LinkerFlavor::Gnu(..)
+ | LinkerFlavor::Unix(..)
+ | LinkerFlavor::EmCc
+ | LinkerFlavor::Bpf
+ | LinkerFlavor::Ptx => LldFlavor::Ld,
+ LinkerFlavor::Darwin(..) => LldFlavor::Ld64,
+ LinkerFlavor::WasmLld(..) => LldFlavor::Wasm,
+ LinkerFlavor::Msvc(..) => LldFlavor::Link,
+ }
+ }
+
+ pub fn is_gnu(self) -> bool {
+ matches!(self, LinkerFlavor::Gnu(..))
+ }
}
macro_rules! linker_flavor_cli_impls {
@@ -635,6 +736,10 @@ pub enum StackProbeType {
}
impl StackProbeType {
+ // LLVM X86 targets (ix86 and x86_64) can use inline-asm stack probes starting with LLVM 16.
+ // Notable past issues were rust#83139 (fixed in 14) and rust#84667 (fixed in 16).
+ const X86: Self = Self::InlineOrCall { min_llvm_version_for_inline: (16, 0, 0) };
+
fn from_json(json: &Json) -> Result<Self, String> {
let object = json.as_object().ok_or_else(|| "expected a JSON object")?;
let kind = object
@@ -1120,6 +1225,8 @@ supported_targets! {
("mipsel-unknown-none", mipsel_unknown_none),
("thumbv4t-none-eabi", thumbv4t_none_eabi),
("armv4t-none-eabi", armv4t_none_eabi),
+ ("thumbv5te-none-eabi", thumbv5te_none_eabi),
+ ("armv5te-none-eabi", armv5te_none_eabi),
("aarch64_be-unknown-linux-gnu", aarch64_be_unknown_linux_gnu),
("aarch64-unknown-linux-gnu_ilp32", aarch64_unknown_linux_gnu_ilp32),
@@ -1252,16 +1359,11 @@ pub struct TargetOptions {
/// Linker to invoke
pub linker: Option<StaticCow<str>>,
/// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed
- /// on the command line. Defaults to `LinkerFlavor::Gcc`.
+ /// on the command line. Defaults to `LinkerFlavor::Gnu(Cc::Yes, Lld::No)`.
pub linker_flavor: LinkerFlavor,
linker_flavor_json: LinkerFlavorCli,
- /// LLD flavor used if `lld` (or `rust-lld`) is specified as a linker
- /// without clarifying its flavor in any way.
- /// FIXME: Merge this into `LinkerFlavor`.
- pub lld_flavor: LldFlavor,
- /// Whether the linker support GNU-like arguments such as -O. Defaults to true.
- /// FIXME: Merge this into `LinkerFlavor`.
- pub linker_is_gnu: bool,
+ lld_flavor_json: LldFlavor,
+ linker_is_gnu_json: bool,
/// Objects to link before and after all other object code.
pub pre_link_objects: CrtObjects,
@@ -1294,7 +1396,7 @@ pub struct TargetOptions {
/// Optional link script applied to `dylib` and `executable` crate types.
/// This is a string containing the script, not a path. Can only be applied
- /// to linkers where `linker_is_gnu` is true.
+ /// to linkers where linker flavor matches `LinkerFlavor::Gnu(..)`.
pub link_script: Option<StaticCow<str>>,
/// Environment variables to be set for the linker invocation.
pub link_env: StaticCow<[(StaticCow<str>, StaticCow<str>)]>,
@@ -1379,6 +1481,8 @@ pub struct TargetOptions {
pub is_like_msvc: bool,
/// Whether a target toolchain is like WASM.
pub is_like_wasm: bool,
+ /// Whether a target toolchain is like Android, implying a Linux kernel and a Bionic libc
+ pub is_like_android: bool,
/// Default supported version of DWARF on this platform.
/// Useful because some platforms (osx, bsd) only want up to DWARF2.
pub default_dwarf_version: u32,
@@ -1567,22 +1671,38 @@ pub struct TargetOptions {
/// Add arguments for the given flavor and also for its "twin" flavors
/// that have a compatible command line interface.
-fn add_link_args(link_args: &mut LinkArgs, flavor: LinkerFlavor, args: &[&'static str]) {
- let mut insert = |flavor| {
- link_args.entry(flavor).or_default().extend(args.iter().copied().map(Cow::Borrowed))
- };
+fn add_link_args_iter(
+ link_args: &mut LinkArgs,
+ flavor: LinkerFlavor,
+ args: impl Iterator<Item = StaticCow<str>> + Clone,
+) {
+ let mut insert = |flavor| link_args.entry(flavor).or_default().extend(args.clone());
insert(flavor);
match flavor {
- LinkerFlavor::Ld => insert(LinkerFlavor::Lld(LldFlavor::Ld)),
- LinkerFlavor::Msvc => insert(LinkerFlavor::Lld(LldFlavor::Link)),
- LinkerFlavor::Lld(LldFlavor::Ld64) | LinkerFlavor::Lld(LldFlavor::Wasm) => {}
- LinkerFlavor::Lld(lld_flavor) => {
- panic!("add_link_args: use non-LLD flavor for {:?}", lld_flavor)
+ LinkerFlavor::Gnu(cc, lld) => {
+ assert_eq!(lld, Lld::No);
+ insert(LinkerFlavor::Gnu(cc, Lld::Yes));
+ }
+ LinkerFlavor::Darwin(cc, lld) => {
+ assert_eq!(lld, Lld::No);
+ insert(LinkerFlavor::Darwin(cc, Lld::Yes));
}
- LinkerFlavor::Gcc | LinkerFlavor::EmCc | LinkerFlavor::Bpf | LinkerFlavor::Ptx => {}
+ LinkerFlavor::Msvc(lld) => {
+ assert_eq!(lld, Lld::No);
+ insert(LinkerFlavor::Msvc(Lld::Yes));
+ }
+ LinkerFlavor::WasmLld(..)
+ | LinkerFlavor::Unix(..)
+ | LinkerFlavor::EmCc
+ | LinkerFlavor::Bpf
+ | LinkerFlavor::Ptx => {}
}
}
+fn add_link_args(link_args: &mut LinkArgs, flavor: LinkerFlavor, args: &[&'static str]) {
+ add_link_args_iter(link_args, flavor, args.iter().copied().map(Cow::Borrowed))
+}
+
impl TargetOptions {
fn link_args(flavor: LinkerFlavor, args: &[&'static str]) -> LinkArgs {
let mut link_args = LinkArgs::new();
@@ -1599,7 +1719,11 @@ impl TargetOptions {
}
fn update_from_cli(&mut self) {
- self.linker_flavor = LinkerFlavor::from_cli(self.linker_flavor_json);
+ self.linker_flavor = LinkerFlavor::from_cli_impl(
+ self.linker_flavor_json,
+ self.lld_flavor_json,
+ self.linker_is_gnu_json,
+ );
for (args, args_json) in [
(&mut self.pre_link_args, &self.pre_link_args_json),
(&mut self.late_link_args, &self.late_link_args_json),
@@ -1607,15 +1731,32 @@ impl TargetOptions {
(&mut self.late_link_args_static, &self.late_link_args_static_json),
(&mut self.post_link_args, &self.post_link_args_json),
] {
- *args = args_json
- .iter()
- .map(|(flavor, args)| (LinkerFlavor::from_cli(*flavor), args.clone()))
- .collect();
+ args.clear();
+ for (flavor, args_json) in args_json {
+ // Cannot use `from_cli` due to borrow checker.
+ let linker_flavor = LinkerFlavor::from_cli_impl(
+ *flavor,
+ self.lld_flavor_json,
+ self.linker_is_gnu_json,
+ );
+ // Normalize to no lld to avoid asserts.
+ let linker_flavor = match linker_flavor {
+ LinkerFlavor::Gnu(cc, _) => LinkerFlavor::Gnu(cc, Lld::No),
+ LinkerFlavor::Darwin(cc, _) => LinkerFlavor::Darwin(cc, Lld::No),
+ LinkerFlavor::Msvc(_) => LinkerFlavor::Msvc(Lld::No),
+ _ => linker_flavor,
+ };
+ if !args.contains_key(&linker_flavor) {
+ add_link_args_iter(args, linker_flavor, args_json.iter().cloned());
+ }
+ }
}
}
fn update_to_cli(&mut self) {
self.linker_flavor_json = self.linker_flavor.to_cli();
+ self.lld_flavor_json = self.linker_flavor.lld_flavor();
+ self.linker_is_gnu_json = self.linker_flavor.is_gnu();
for (args, args_json) in [
(&self.pre_link_args, &mut self.pre_link_args_json),
(&self.late_link_args, &mut self.late_link_args_json),
@@ -1642,10 +1783,10 @@ impl Default for TargetOptions {
abi: "".into(),
vendor: "unknown".into(),
linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.into()),
- linker_flavor: LinkerFlavor::Gcc,
+ linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No),
linker_flavor_json: LinkerFlavorCli::Gcc,
- lld_flavor: LldFlavor::Ld,
- linker_is_gnu: true,
+ lld_flavor_json: LldFlavor::Ld,
+ linker_is_gnu_json: true,
link_script: None,
asm_args: cvs![],
cpu: "generic".into(),
@@ -1671,6 +1812,7 @@ impl Default for TargetOptions {
is_like_windows: false,
is_like_msvc: false,
is_like_wasm: false,
+ is_like_android: false,
default_dwarf_version: 4,
allows_weak_linkage: true,
has_rpath: false,
@@ -1913,6 +2055,12 @@ impl Target {
base.$key_name = s;
}
} );
+ ($key_name:ident = $json_name:expr, bool) => ( {
+ let name = $json_name;
+ if let Some(s) = obj.remove(name).and_then(|b| b.as_bool()) {
+ base.$key_name = s;
+ }
+ } );
($key_name:ident, u64) => ( {
let name = (stringify!($key_name)).replace("_", "-");
if let Some(s) = obj.remove(&name).and_then(|j| Json::as_u64(&j)) {
@@ -2084,9 +2232,9 @@ impl Target {
.map(|s| s.to_string().into());
}
} );
- ($key_name:ident, LldFlavor) => ( {
- let name = (stringify!($key_name)).replace("_", "-");
- obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
+ ($key_name:ident = $json_name:expr, LldFlavor) => ( {
+ let name = $json_name;
+ obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
if let Some(flavor) = LldFlavor::from_str(&s) {
base.$key_name = flavor;
} else {
@@ -2280,8 +2428,8 @@ impl Target {
key!(vendor);
key!(linker, optional);
key!(linker_flavor_json = "linker-flavor", LinkerFlavor)?;
- key!(lld_flavor, LldFlavor)?;
- key!(linker_is_gnu, bool);
+ key!(lld_flavor_json = "lld-flavor", LldFlavor)?;
+ key!(linker_is_gnu_json = "linker-is-gnu", bool);
key!(pre_link_objects = "pre-link-objects", link_objects);
key!(post_link_objects = "post-link-objects", link_objects);
key!(pre_link_objects_self_contained = "pre-link-objects-fallback", link_objects);
@@ -2318,6 +2466,7 @@ impl Target {
key!(is_like_windows, bool);
key!(is_like_msvc, bool);
key!(is_like_wasm, bool);
+ key!(is_like_android, bool);
key!(default_dwarf_version, u32);
key!(allows_weak_linkage, bool);
key!(has_rpath, bool);
@@ -2529,8 +2678,8 @@ impl ToJson for Target {
target_option_val!(vendor);
target_option_val!(linker);
target_option_val!(linker_flavor_json, "linker-flavor");
- target_option_val!(lld_flavor);
- target_option_val!(linker_is_gnu);
+ target_option_val!(lld_flavor_json, "lld-flavor");
+ target_option_val!(linker_is_gnu_json, "linker-is-gnu");
target_option_val!(pre_link_objects);
target_option_val!(post_link_objects);
target_option_val!(pre_link_objects_self_contained, "pre-link-objects-fallback");
@@ -2568,6 +2717,7 @@ impl ToJson for Target {
target_option_val!(is_like_windows);
target_option_val!(is_like_msvc);
target_option_val!(is_like_wasm);
+ target_option_val!(is_like_android);
target_option_val!(default_dwarf_version);
target_option_val!(allows_weak_linkage);
target_option_val!(has_rpath);
diff --git a/compiler/rustc_target/src/spec/msp430_none_elf.rs b/compiler/rustc_target/src/spec/msp430_none_elf.rs
index 6b09386ae..251fd2a0a 100644
--- a/compiler/rustc_target/src/spec/msp430_none_elf.rs
+++ b/compiler/rustc_target/src/spec/msp430_none_elf.rs
@@ -1,4 +1,4 @@
-use crate::spec::{cvs, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{cvs, Cc, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -16,7 +16,7 @@ pub fn target() -> Target {
// dependency on this specific gcc.
asm_args: cvs!["-mcpu=msp430"],
linker: Some("msp430-elf-gcc".into()),
- linker_is_gnu: false,
+ linker_flavor: LinkerFlavor::Unix(Cc::Yes),
// There are no atomic CAS instructions available in the MSP430
// instruction set, and the LLVM backend doesn't currently support
diff --git a/compiler/rustc_target/src/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs
index b3cd38a6e..1dad9133e 100644
--- a/compiler/rustc_target/src/spec/msvc_base.rs
+++ b/compiler/rustc_target/src/spec/msvc_base.rs
@@ -1,17 +1,15 @@
-use crate::spec::{DebuginfoKind, LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions};
+use crate::spec::{DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions};
use std::borrow::Cow;
pub fn opts() -> TargetOptions {
// Suppress the verbose logo and authorship debugging output, which would needlessly
// clog any log files.
- let pre_link_args = TargetOptions::link_args(LinkerFlavor::Msvc, &["/NOLOGO"]);
+ let pre_link_args = TargetOptions::link_args(LinkerFlavor::Msvc(Lld::No), &["/NOLOGO"]);
TargetOptions {
- linker_flavor: LinkerFlavor::Msvc,
+ linker_flavor: LinkerFlavor::Msvc(Lld::No),
is_like_windows: true,
is_like_msvc: true,
- lld_flavor: LldFlavor::Link,
- linker_is_gnu: false,
pre_link_args,
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
index 6ab3a8b7e..b0582b235 100644
--- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
+++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
@@ -13,7 +13,6 @@ pub fn target() -> Target {
linker_flavor: LinkerFlavor::Ptx,
// The linker can be installed from `crates.io`.
linker: Some("rust-ptx-linker".into()),
- linker_is_gnu: false,
// With `ptx-linker` approach, it can be later overridden via link flags.
cpu: "sm_30".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
index 803453c4a..08b273207 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
@@ -1,11 +1,12 @@
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::freebsd_base::opts();
base.cpu = "ppc64".into();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
base.max_atomic_width = Some(64);
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "powerpc64-unknown-freebsd".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
index 5413c4f33..ce64de861 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
@@ -1,15 +1,12 @@
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, RelroLevel, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts();
base.cpu = "ppc64".into();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
base.max_atomic_width = Some(64);
-
- // ld.so in at least RHEL6 on ppc64 has a bug related to BIND_NOW, so only enable partial RELRO
- // for now. https://github.com/rust-lang/rust/pull/43170#issuecomment-315411474
- base.relro_level = RelroLevel::Partial;
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "powerpc64-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
index 159335eb6..81286a668 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
@@ -1,11 +1,12 @@
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::linux_musl_base::opts();
base.cpu = "ppc64".into();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
base.max_atomic_width = Some(64);
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "powerpc64-unknown-linux-musl".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs
index 9cb3a67dc..7232dce3e 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs
@@ -1,11 +1,12 @@
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::openbsd_base::opts();
base.cpu = "ppc64".into();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
base.max_atomic_width = Some(64);
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "powerpc64-unknown-openbsd".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
index b7420d232..10da7872c 100644
--- a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
@@ -1,11 +1,12 @@
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::vxworks_base::opts();
base.cpu = "ppc64".into();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
base.max_atomic_width = Some(64);
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "powerpc64-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs
index a3d180043..8c941e106 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs
@@ -1,10 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::freebsd_base::opts();
base.cpu = "ppc64le".into();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
base.max_atomic_width = Some(64);
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "powerpc64le-unknown-freebsd".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
index e18ff3be4..fd896e086 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
@@ -1,10 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts();
base.cpu = "ppc64le".into();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
base.max_atomic_width = Some(64);
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "powerpc64le-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
index b84943d23..3cffcf497 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
@@ -1,10 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::linux_musl_base::opts();
base.cpu = "ppc64le".into();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
base.max_atomic_width = Some(64);
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "powerpc64le-unknown-linux-musl".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs
index 75ac66c27..342f321bd 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs
@@ -1,11 +1,15 @@
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::freebsd_base::opts();
// Extra hint to linker that we are generating secure-PLT code.
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "--target=powerpc-unknown-freebsd13.0"]);
+ base.add_pre_link_args(
+ LinkerFlavor::Gnu(Cc::Yes, Lld::No),
+ &["-m32", "--target=powerpc-unknown-freebsd13.0"],
+ );
base.max_atomic_width = Some(32);
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "powerpc-unknown-freebsd13.0".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
index 6686a0bbf..c8c61dc46 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
@@ -1,10 +1,11 @@
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]);
base.max_atomic_width = Some(32);
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "powerpc-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
index 6a250f4b5..5c51ec91f 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
@@ -1,10 +1,11 @@
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-mspe"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-mspe"]);
base.max_atomic_width = Some(32);
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "powerpc-unknown-linux-gnuspe".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
index 34200c679..fc7d802cb 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
@@ -1,10 +1,11 @@
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::linux_musl_base::opts();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]);
base.max_atomic_width = Some(32);
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "powerpc-unknown-linux-musl".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
index 60661ef9b..912149c79 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
@@ -1,10 +1,11 @@
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::netbsd_base::opts();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]);
base.max_atomic_width = Some(32);
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "powerpc-unknown-netbsd".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs
index ad2c3d40f..dec85f996 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs
@@ -1,10 +1,11 @@
use crate::abi::Endian;
-use crate::spec::Target;
+use crate::spec::{StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::openbsd_base::opts();
base.endian = Endian::Big;
base.max_atomic_width = Some(32);
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "powerpc-unknown-openbsd".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
index 3f24966e0..a8c1c2a61 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
@@ -1,10 +1,11 @@
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::vxworks_base::opts();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32", "--secure-plt"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32", "--secure-plt"]);
base.max_atomic_width = Some(32);
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "powerpc-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
index 0f04f41f9..abb8d13da 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
@@ -1,10 +1,11 @@
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::vxworks_base::opts();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-mspe", "--secure-plt"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-mspe", "--secure-plt"]);
base.max_atomic_width = Some(32);
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "powerpc-unknown-linux-gnuspe".into(),
diff --git a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
index 232139db6..75a65a268 100644
--- a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
@@ -1,5 +1,4 @@
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -9,7 +8,7 @@ pub fn target() -> Target {
arch: "riscv32".into(),
options: TargetOptions {
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
cpu: "generic-rv32".into(),
max_atomic_width: Some(0),
diff --git a/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs
index 3e5d2887f..f2242bbe0 100644
--- a/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs
@@ -1,5 +1,4 @@
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -9,7 +8,7 @@ pub fn target() -> Target {
arch: "riscv32".into(),
options: TargetOptions {
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
cpu: "generic-rv32".into(),
max_atomic_width: Some(0),
diff --git a/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs
index 99317b9f1..55c6e4d16 100644
--- a/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs
@@ -1,5 +1,4 @@
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -9,7 +8,7 @@ pub fn target() -> Target {
arch: "riscv32".into(),
options: TargetOptions {
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
cpu: "generic-rv32".into(),
max_atomic_width: Some(32),
diff --git a/compiler/rustc_target/src/spec/riscv32imac_unknown_xous_elf.rs b/compiler/rustc_target/src/spec/riscv32imac_unknown_xous_elf.rs
index a5de645c9..a263e5d5c 100644
--- a/compiler/rustc_target/src/spec/riscv32imac_unknown_xous_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32imac_unknown_xous_elf.rs
@@ -1,5 +1,4 @@
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -10,7 +9,7 @@ pub fn target() -> Target {
options: TargetOptions {
os: "xous".into(),
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
cpu: "generic-rv32".into(),
max_atomic_width: Some(32),
diff --git a/compiler/rustc_target/src/spec/riscv32imc_esp_espidf.rs b/compiler/rustc_target/src/spec/riscv32imc_esp_espidf.rs
index 03baef65c..25638a092 100644
--- a/compiler/rustc_target/src/spec/riscv32imc_esp_espidf.rs
+++ b/compiler/rustc_target/src/spec/riscv32imc_esp_espidf.rs
@@ -1,5 +1,4 @@
-use crate::spec::{cvs, Target, TargetOptions};
-use crate::spec::{LinkerFlavor, PanicStrategy, RelocModel};
+use crate::spec::{cvs, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -13,7 +12,6 @@ pub fn target() -> Target {
os: "espidf".into(),
env: "newlib".into(),
vendor: "espressif".into(),
- linker_flavor: LinkerFlavor::Gcc,
linker: Some("riscv32-esp-elf-gcc".into()),
cpu: "generic-rv32".into(),
diff --git a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
index bf510d204..01e773fae 100644
--- a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
@@ -1,5 +1,4 @@
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -9,7 +8,7 @@ pub fn target() -> Target {
arch: "riscv32".into(),
options: TargetOptions {
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
cpu: "generic-rv32".into(),
max_atomic_width: Some(0),
diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs
index 03b3cfd1e..67806d578 100644
--- a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs
@@ -1,5 +1,5 @@
-use crate::spec::{CodeModel, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy};
+use crate::spec::{RelocModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -9,7 +9,7 @@ pub fn target() -> Target {
arch: "riscv64".into(),
options: TargetOptions {
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
llvm_abiname: "lp64d".into(),
cpu: "generic-rv64".into(),
diff --git a/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs
index 2a94c9dd2..f371e09be 100644
--- a/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs
@@ -1,5 +1,5 @@
-use crate::spec::{CodeModel, Target, TargetOptions};
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
+use crate::spec::{Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy};
+use crate::spec::{RelocModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -9,7 +9,7 @@ pub fn target() -> Target {
arch: "riscv64".into(),
options: TargetOptions {
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
cpu: "generic-rv64".into(),
max_atomic_width: Some(64),
diff --git a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
index 8757bbed8..cda88de0e 100644
--- a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
@@ -1,22 +1,23 @@
use crate::abi::Endian;
-use crate::spec::Target;
+use crate::spec::{StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts();
base.endian = Endian::Big;
// z10 is the oldest CPU supported by LLVM
base.cpu = "z10".into();
- // FIXME: The data_layout string below and the ABI implementation in
- // cabi_s390x.rs are for now hard-coded to assume the no-vector ABI.
- // Pass the -vector feature string to LLVM to respect this assumption.
+ // FIXME: The ABI implementation in cabi_s390x.rs is for now hard-coded to assume the no-vector
+ // ABI. Pass the -vector feature string to LLVM to respect this assumption. On LLVM < 16, we
+ // also strip v128 from the data_layout below to match the older LLVM's expectation.
base.features = "-vector".into();
base.max_atomic_width = Some(64);
base.min_global_align = Some(16);
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "s390x-unknown-linux-gnu".into(),
pointer_width: 64,
- data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64".into(),
+ data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64".into(),
arch: "s390x".into(),
options: base,
}
diff --git a/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs
index 4c855271a..91e63aee5 100644
--- a/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/s390x_unknown_linux_musl.rs
@@ -1,23 +1,24 @@
use crate::abi::Endian;
-use crate::spec::Target;
+use crate::spec::{StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::linux_musl_base::opts();
base.endian = Endian::Big;
// z10 is the oldest CPU supported by LLVM
base.cpu = "z10".into();
- // FIXME: The data_layout string below and the ABI implementation in
- // cabi_s390x.rs are for now hard-coded to assume the no-vector ABI.
- // Pass the -vector feature string to LLVM to respect this assumption.
+ // FIXME: The ABI implementation in cabi_s390x.rs is for now hard-coded to assume the no-vector
+ // ABI. Pass the -vector feature string to LLVM to respect this assumption. On LLVM < 16, we
+ // also strip v128 from the data_layout below to match the older LLVM's expectation.
base.features = "-vector".into();
base.max_atomic_width = Some(64);
base.min_global_align = Some(16);
base.static_position_independent_executables = true;
+ base.stack_probes = StackProbeType::Inline;
Target {
llvm_target: "s390x-unknown-linux-musl".into(),
pointer_width: 64,
- data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64".into(),
+ data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64".into(),
arch: "s390x".into(),
options: base,
}
diff --git a/compiler/rustc_target/src/spec/solaris_base.rs b/compiler/rustc_target/src/spec/solaris_base.rs
index b7e8e8cf7..f97cdb4fb 100644
--- a/compiler/rustc_target/src/spec/solaris_base.rs
+++ b/compiler/rustc_target/src/spec/solaris_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::{cvs, TargetOptions};
+use crate::spec::{cvs, Cc, LinkerFlavor, TargetOptions};
pub fn opts() -> TargetOptions {
TargetOptions {
@@ -7,7 +7,7 @@ pub fn opts() -> TargetOptions {
has_rpath: true,
families: cvs!["unix"],
is_like_solaris: true,
- linker_is_gnu: false,
+ linker_flavor: LinkerFlavor::Unix(Cc::Yes),
limit_rdylib_exports: false, // Linker doesn't support this
eh_frame_header: false,
diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
index 836ab0e37..38ab066b0 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
@@ -1,10 +1,10 @@
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::netbsd_base::opts();
base.cpu = "v9".into();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
base.max_atomic_width = Some(64);
Target {
diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
index 4a192df39..06a5f782a 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
@@ -1,11 +1,11 @@
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target};
pub fn target() -> Target {
let mut base = super::openbsd_base::opts();
base.endian = Endian::Big;
base.cpu = "v9".into();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
base.max_atomic_width = Some(64);
Target {
diff --git a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
index ea4fafa4b..12968abda 100644
--- a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
@@ -1,12 +1,12 @@
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target};
pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts();
base.endian = Endian::Big;
base.cpu = "v9".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-mv8plus"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-mv8plus"]);
Target {
llvm_target: "sparc-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
index aac09181a..440194ef2 100644
--- a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
+++ b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
@@ -1,10 +1,10 @@
use crate::abi::Endian;
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{Cc, LinkerFlavor, Target};
pub fn target() -> Target {
let mut base = super::solaris_base::opts();
base.endian = Endian::Big;
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+ base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64"]);
// llvm calls this "v9"
base.cpu = "v9".into();
base.vendor = "sun".into();
diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs
index 0af599916..172da0ed5 100644
--- a/compiler/rustc_target/src/spec/tests/tests_impl.rs
+++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs
@@ -19,11 +19,13 @@ impl Target {
assert!(self.is_like_windows);
}
- // Check that default linker flavor and lld flavor are compatible
- // with some other key properties.
- assert_eq!(self.is_like_osx, matches!(self.lld_flavor, LldFlavor::Ld64));
- assert_eq!(self.is_like_msvc, matches!(self.lld_flavor, LldFlavor::Link));
- assert_eq!(self.is_like_wasm, matches!(self.lld_flavor, LldFlavor::Wasm));
+ // Check that default linker flavor is compatible with some other key properties.
+ assert_eq!(self.is_like_osx, matches!(self.linker_flavor, LinkerFlavor::Darwin(..)));
+ assert_eq!(self.is_like_msvc, matches!(self.linker_flavor, LinkerFlavor::Msvc(..)));
+ assert_eq!(
+ self.is_like_wasm && self.os != "emscripten",
+ matches!(self.linker_flavor, LinkerFlavor::WasmLld(..))
+ );
assert_eq!(self.os == "emscripten", matches!(self.linker_flavor, LinkerFlavor::EmCc));
assert_eq!(self.arch == "bpf", matches!(self.linker_flavor, LinkerFlavor::Bpf));
assert_eq!(self.arch == "nvptx64", matches!(self.linker_flavor, LinkerFlavor::Ptx));
@@ -38,44 +40,25 @@ impl Target {
for (&flavor, flavor_args) in args {
assert!(!flavor_args.is_empty());
// Check that flavors mentioned in link args are compatible with the default flavor.
- match (self.linker_flavor, self.lld_flavor) {
- (
- LinkerFlavor::Ld | LinkerFlavor::Lld(LldFlavor::Ld) | LinkerFlavor::Gcc,
- LldFlavor::Ld,
- ) => {
- assert_matches!(
- flavor,
- LinkerFlavor::Ld | LinkerFlavor::Lld(LldFlavor::Ld) | LinkerFlavor::Gcc
- )
- }
- (LinkerFlavor::Gcc, LldFlavor::Ld64) => {
- assert_matches!(
- flavor,
- LinkerFlavor::Lld(LldFlavor::Ld64) | LinkerFlavor::Gcc
- )
+ match self.linker_flavor {
+ LinkerFlavor::Gnu(..) => {
+ assert_matches!(flavor, LinkerFlavor::Gnu(..));
}
- (LinkerFlavor::Msvc | LinkerFlavor::Lld(LldFlavor::Link), LldFlavor::Link) => {
- assert_matches!(
- flavor,
- LinkerFlavor::Msvc | LinkerFlavor::Lld(LldFlavor::Link)
- )
+ LinkerFlavor::Darwin(..) => {
+ assert_matches!(flavor, LinkerFlavor::Darwin(..))
}
- (LinkerFlavor::Lld(LldFlavor::Wasm) | LinkerFlavor::Gcc, LldFlavor::Wasm) => {
- assert_matches!(
- flavor,
- LinkerFlavor::Lld(LldFlavor::Wasm) | LinkerFlavor::Gcc
- )
+ LinkerFlavor::WasmLld(..) => {
+ assert_matches!(flavor, LinkerFlavor::WasmLld(..))
}
- (LinkerFlavor::EmCc, LldFlavor::Wasm) => {
- assert_matches!(flavor, LinkerFlavor::EmCc)
+ LinkerFlavor::Unix(..) => {
+ assert_matches!(flavor, LinkerFlavor::Unix(..));
}
- (LinkerFlavor::Bpf, LldFlavor::Ld) => {
- assert_matches!(flavor, LinkerFlavor::Bpf)
+ LinkerFlavor::Msvc(..) => {
+ assert_matches!(flavor, LinkerFlavor::Msvc(..))
}
- (LinkerFlavor::Ptx, LldFlavor::Ld) => {
- assert_matches!(flavor, LinkerFlavor::Ptx)
+ LinkerFlavor::EmCc | LinkerFlavor::Bpf | LinkerFlavor::Ptx => {
+ assert_eq!(flavor, self.linker_flavor)
}
- flavors => unreachable!("unexpected flavor combination: {:?}", flavors),
}
// Check that link args for cc and non-cc versions of flavors are consistent.
@@ -88,25 +71,29 @@ impl Target {
}
}
};
+
match self.linker_flavor {
- LinkerFlavor::Gcc => match self.lld_flavor {
- LldFlavor::Ld => {
- check_noncc(LinkerFlavor::Ld);
- check_noncc(LinkerFlavor::Lld(LldFlavor::Ld));
- }
- LldFlavor::Ld64 => check_noncc(LinkerFlavor::Lld(LldFlavor::Ld64)),
- LldFlavor::Wasm => check_noncc(LinkerFlavor::Lld(LldFlavor::Wasm)),
- LldFlavor::Link => {}
- },
+ LinkerFlavor::Gnu(Cc::Yes, lld) => check_noncc(LinkerFlavor::Gnu(Cc::No, lld)),
+ LinkerFlavor::WasmLld(Cc::Yes) => check_noncc(LinkerFlavor::WasmLld(Cc::No)),
+ LinkerFlavor::Unix(Cc::Yes) => check_noncc(LinkerFlavor::Unix(Cc::No)),
_ => {}
}
}
// Check that link args for lld and non-lld versions of flavors are consistent.
- assert_eq!(args.get(&LinkerFlavor::Ld), args.get(&LinkerFlavor::Lld(LldFlavor::Ld)));
+ for cc in [Cc::No, Cc::Yes] {
+ assert_eq!(
+ args.get(&LinkerFlavor::Gnu(cc, Lld::No)),
+ args.get(&LinkerFlavor::Gnu(cc, Lld::Yes)),
+ );
+ assert_eq!(
+ args.get(&LinkerFlavor::Darwin(cc, Lld::No)),
+ args.get(&LinkerFlavor::Darwin(cc, Lld::Yes)),
+ );
+ }
assert_eq!(
- args.get(&LinkerFlavor::Msvc),
- args.get(&LinkerFlavor::Lld(LldFlavor::Link)),
+ args.get(&LinkerFlavor::Msvc(Lld::No)),
+ args.get(&LinkerFlavor::Msvc(Lld::Yes)),
);
}
diff --git a/compiler/rustc_target/src/spec/thumb_base.rs b/compiler/rustc_target/src/spec/thumb_base.rs
index 049142b89..000766c57 100644
--- a/compiler/rustc_target/src/spec/thumb_base.rs
+++ b/compiler/rustc_target/src/spec/thumb_base.rs
@@ -27,13 +27,12 @@
// differentiate these targets from our other `arm(v7)-*-*-gnueabi(hf)` targets in the context of
// build scripts / gcc flags.
-use crate::spec::TargetOptions;
-use crate::spec::{FramePointer, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
+use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, PanicStrategy, RelocModel, TargetOptions};
pub fn opts() -> TargetOptions {
// See rust-lang/rfcs#1645 for a discussion about these defaults
TargetOptions {
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
// In most cases, LLD is good enough
linker: Some("rust-lld".into()),
// Because these devices have very little resources having an unwinder is too onerous so we
diff --git a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
index bdaaed8b5..5a3e4c88d 100644
--- a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
@@ -16,9 +16,8 @@
//! The default link script is very likely wrong, so you should use
//! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.
-use crate::spec::{
- cvs, FramePointer, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions,
-};
+use crate::spec::{cvs, Cc, FramePointer, LinkerFlavor, Lld};
+use crate::spec::{PanicStrategy, RelocModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -37,7 +36,7 @@ pub fn target() -> Target {
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
options: TargetOptions {
abi: "eabi".into(),
- linker_flavor: LinkerFlavor::Ld,
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::No),
linker: Some("arm-none-eabi-ld".into()),
// extra args passed to the external assembler (assuming `arm-none-eabi-as`):
diff --git a/compiler/rustc_target/src/spec/thumbv5te_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv5te_none_eabi.rs
new file mode 100644
index 000000000..021b0e0eb
--- /dev/null
+++ b/compiler/rustc_target/src/spec/thumbv5te_none_eabi.rs
@@ -0,0 +1,41 @@
+//! Targets the ARMv5TE, with code as `t32` code by default.
+
+use crate::spec::{cvs, FramePointer, Target, TargetOptions};
+
+pub fn target() -> Target {
+ Target {
+ llvm_target: "thumbv5te-none-eabi".into(),
+ pointer_width: 32,
+ arch: "arm".into(),
+ /* Data layout args are '-' separated:
+ * little endian
+ * stack is 64-bit aligned (EABI)
+ * pointers are 32-bit
+ * i64 must be 64-bit aligned (EABI)
+ * mangle names with ELF style
+ * native integers are 32-bit
+ * All other elements are default
+ */
+ data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
+
+ options: TargetOptions {
+ abi: "eabi".into(),
+ // extra args passed to the external assembler (assuming `arm-none-eabi-as`):
+ // * activate t32/a32 interworking
+ // * use arch ARMv5TE
+ // * use little-endian
+ asm_args: cvs!["-mthumb-interwork", "-march=armv5te", "-mlittle-endian",],
+ // minimum extra features, these cannot be disabled via -C
+ // Also force-enable 32-bit atomics, which allows the use of atomic load/store only.
+ // The resulting atomics are ABI incompatible with atomics backed by libatomic.
+ features: "+soft-float,+strict-align,+atomics-32".into(),
+ frame_pointer: FramePointer::MayOmit,
+ main_needs_argc_argv: false,
+ // don't have atomic compare-and-swap
+ atomic_cas: false,
+ has_thumb_interworking: true,
+
+ ..super::thumb_base::opts()
+ },
+ }
+}
diff --git a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs
index 4d09d3a4d..f1be274f0 100644
--- a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, Lld, PanicStrategy, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::windows_msvc_base::opts();
@@ -9,7 +9,7 @@ pub fn target() -> Target {
// should be smart enough to insert branch islands only
// where necessary, but this is not the observed behavior.
// Disabling the LBR optimization works around the issue.
- base.add_pre_link_args(LinkerFlavor::Msvc, &["/OPT:NOLBR"]);
+ base.add_pre_link_args(LinkerFlavor::Msvc(Lld::No), &["/OPT:NOLBR"]);
Target {
llvm_target: "thumbv7a-pc-windows-msvc".into(),
diff --git a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs
index 4cad9e183..8d80fcd5f 100644
--- a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions};
// This target if is for the Android v7a ABI in thumb mode with
// NEON unconditionally enabled and, therefore, with 32 FPU registers
@@ -10,7 +10,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::android_base::opts();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-march=armv7-a"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-march=armv7-a"]);
Target {
llvm_target: "armv7-none-linux-android".into(),
pointer_width: 32,
diff --git a/compiler/rustc_target/src/spec/uefi_msvc_base.rs b/compiler/rustc_target/src/spec/uefi_msvc_base.rs
index 99af7d85e..8968d3c8f 100644
--- a/compiler/rustc_target/src/spec/uefi_msvc_base.rs
+++ b/compiler/rustc_target/src/spec/uefi_msvc_base.rs
@@ -9,14 +9,13 @@
// the timer-interrupt. Device-drivers are required to use polling-based models. Furthermore, all
// code runs in the same environment, no process separation is supported.
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy};
-use crate::spec::{StackProbeType, TargetOptions};
+use crate::spec::{LinkerFlavor, Lld, PanicStrategy, StackProbeType, TargetOptions};
pub fn opts() -> TargetOptions {
let mut base = super::msvc_base::opts();
base.add_pre_link_args(
- LinkerFlavor::Msvc,
+ LinkerFlavor::Msvc(Lld::No),
&[
// Non-standard subsystems have no default entry-point in PE+ files. We have to define
// one. "efi_main" seems to be a common choice amongst other implementations and the
@@ -37,7 +36,7 @@ pub fn opts() -> TargetOptions {
TargetOptions {
os: "uefi".into(),
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Link),
+ linker_flavor: LinkerFlavor::Msvc(Lld::Yes),
disable_redzone: true,
exe_suffix: ".efi".into(),
allows_weak_linkage: false,
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
index 4e2927dd9..8dad941b5 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
@@ -10,14 +10,12 @@
//! This target is more or less managed by the Rust and WebAssembly Working
//! Group nowadays at <https://github.com/rustwasm>.
-use super::wasm_base;
-use super::{LinkerFlavor, LldFlavor, Target};
+use super::{wasm_base, Cc, LinkerFlavor, Target};
use crate::spec::abi::Abi;
pub fn target() -> Target {
let mut options = wasm_base::options();
options.os = "unknown".into();
- options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm);
// This is a default for backwards-compatibility with the original
// definition of this target oh-so-long-ago. Once the "wasm" ABI is
@@ -30,7 +28,7 @@ pub fn target() -> Target {
options.default_adjusted_cabi = Some(Abi::Wasm);
options.add_pre_link_args(
- LinkerFlavor::Lld(LldFlavor::Wasm),
+ LinkerFlavor::WasmLld(Cc::No),
&[
// For now this target just never has an entry symbol no matter the output
// type, so unconditionally pass this.
@@ -44,7 +42,7 @@ pub fn target() -> Target {
],
);
options.add_pre_link_args(
- LinkerFlavor::Gcc,
+ LinkerFlavor::WasmLld(Cc::Yes),
&[
// Make sure clang uses LLD as its linker and is configured appropriately
// otherwise
diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs
index 9c30487f4..93a956403 100644
--- a/compiler/rustc_target/src/spec/wasm32_wasi.rs
+++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs
@@ -72,15 +72,13 @@
//! best we can with this target. Don't start relying on too much here unless
//! you know what you're getting in to!
-use super::wasm_base;
-use super::{crt_objects, LinkerFlavor, LldFlavor, Target};
+use super::{crt_objects, wasm_base, Cc, LinkerFlavor, Target};
pub fn target() -> Target {
let mut options = wasm_base::options();
options.os = "wasi".into();
- options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm);
- options.add_pre_link_args(LinkerFlavor::Gcc, &["--target=wasm32-wasi"]);
+ options.add_pre_link_args(LinkerFlavor::WasmLld(Cc::Yes), &["--target=wasm32-wasi"]);
options.pre_link_objects_self_contained = crt_objects::pre_wasi_self_contained();
options.post_link_objects_self_contained = crt_objects::post_wasi_self_contained();
diff --git a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
index 5211f7707..3fda398d2 100644
--- a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
@@ -7,16 +7,14 @@
//! the standard library is available, most of it returns an error immediately
//! (e.g. trying to create a TCP stream or something like that).
-use super::wasm_base;
-use super::{LinkerFlavor, LldFlavor, Target};
+use super::{wasm_base, Cc, LinkerFlavor, Target};
pub fn target() -> Target {
let mut options = wasm_base::options();
options.os = "unknown".into();
- options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm);
options.add_pre_link_args(
- LinkerFlavor::Lld(LldFlavor::Wasm),
+ LinkerFlavor::WasmLld(Cc::No),
&[
// For now this target just never has an entry symbol no matter the output
// type, so unconditionally pass this.
@@ -25,7 +23,7 @@ pub fn target() -> Target {
],
);
options.add_pre_link_args(
- LinkerFlavor::Gcc,
+ LinkerFlavor::WasmLld(Cc::Yes),
&[
// Make sure clang uses LLD as its linker and is configured appropriately
// otherwise
diff --git a/compiler/rustc_target/src/spec/wasm_base.rs b/compiler/rustc_target/src/spec/wasm_base.rs
index 28a07701e..528a84a8b 100644
--- a/compiler/rustc_target/src/spec/wasm_base.rs
+++ b/compiler/rustc_target/src/spec/wasm_base.rs
@@ -1,5 +1,5 @@
use super::crt_objects::LinkSelfContainedDefault;
-use super::{cvs, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel};
+use super::{cvs, Cc, LinkerFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel};
pub fn options() -> TargetOptions {
macro_rules! args {
@@ -49,8 +49,8 @@ pub fn options() -> TargetOptions {
};
}
- let mut pre_link_args = TargetOptions::link_args(LinkerFlavor::Lld(LldFlavor::Wasm), args!(""));
- super::add_link_args(&mut pre_link_args, LinkerFlavor::Gcc, args!("-Wl,"));
+ let mut pre_link_args = TargetOptions::link_args(LinkerFlavor::WasmLld(Cc::No), args!(""));
+ super::add_link_args(&mut pre_link_args, LinkerFlavor::WasmLld(Cc::Yes), args!("-Wl,"));
TargetOptions {
is_like_wasm: true,
@@ -91,8 +91,7 @@ pub fn options() -> TargetOptions {
// we use the LLD shipped with the Rust toolchain by default
linker: Some("rust-lld".into()),
- lld_flavor: LldFlavor::Wasm,
- linker_is_gnu: false,
+ linker_flavor: LinkerFlavor::WasmLld(Cc::No),
pre_link_args,
diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs
index 81d44a963..a32ca469b 100644
--- a/compiler/rustc_target/src/spec/windows_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs
@@ -1,10 +1,10 @@
use crate::spec::crt_objects::{self, LinkSelfContainedDefault};
-use crate::spec::{cvs, DebuginfoKind, LinkerFlavor, SplitDebuginfo, TargetOptions};
+use crate::spec::{cvs, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions};
use std::borrow::Cow;
pub fn opts() -> TargetOptions {
let mut pre_link_args = TargetOptions::link_args(
- LinkerFlavor::Ld,
+ LinkerFlavor::Gnu(Cc::No, Lld::No),
&[
// Enable ASLR
"--dynamicbase",
@@ -14,7 +14,7 @@ pub fn opts() -> TargetOptions {
);
super::add_link_args(
&mut pre_link_args,
- LinkerFlavor::Gcc,
+ LinkerFlavor::Gnu(Cc::Yes, Lld::No),
&[
// Tell GCC to avoid linker plugins, because we are not bundling
// them with Windows installer, and Rust does its own LTO anyways.
@@ -42,23 +42,33 @@ pub fn opts() -> TargetOptions {
"-luser32",
"-lkernel32",
];
- let mut late_link_args = TargetOptions::link_args(LinkerFlavor::Ld, mingw_libs);
- super::add_link_args(&mut late_link_args, LinkerFlavor::Gcc, mingw_libs);
+ let mut late_link_args =
+ TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), mingw_libs);
+ super::add_link_args(&mut late_link_args, LinkerFlavor::Gnu(Cc::Yes, Lld::No), mingw_libs);
// If any of our crates are dynamically linked then we need to use
// the shared libgcc_s-dw2-1.dll. This is required to support
// unwinding across DLL boundaries.
let dynamic_unwind_libs = &["-lgcc_s"];
let mut late_link_args_dynamic =
- TargetOptions::link_args(LinkerFlavor::Ld, dynamic_unwind_libs);
- super::add_link_args(&mut late_link_args_dynamic, LinkerFlavor::Gcc, dynamic_unwind_libs);
+ TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), dynamic_unwind_libs);
+ super::add_link_args(
+ &mut late_link_args_dynamic,
+ LinkerFlavor::Gnu(Cc::Yes, Lld::No),
+ dynamic_unwind_libs,
+ );
// If all of our crates are statically linked then we can get away
// with statically linking the libgcc unwinding code. This allows
// binaries to be redistributed without the libgcc_s-dw2-1.dll
// dependency, but unfortunately break unwinding across DLL
// boundaries when unwinding across FFI boundaries.
let static_unwind_libs = &["-lgcc_eh", "-l:libpthread.a"];
- let mut late_link_args_static = TargetOptions::link_args(LinkerFlavor::Ld, static_unwind_libs);
- super::add_link_args(&mut late_link_args_static, LinkerFlavor::Gcc, static_unwind_libs);
+ let mut late_link_args_static =
+ TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), static_unwind_libs);
+ super::add_link_args(
+ &mut late_link_args_static,
+ LinkerFlavor::Gnu(Cc::Yes, Lld::No),
+ static_unwind_libs,
+ );
TargetOptions {
os: "windows".into(),
diff --git a/compiler/rustc_target/src/spec/windows_gnullvm_base.rs b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs
index f30be2549..58210c75a 100644
--- a/compiler/rustc_target/src/spec/windows_gnullvm_base.rs
+++ b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs
@@ -1,15 +1,17 @@
-use crate::spec::{cvs, LinkerFlavor, TargetOptions};
+use crate::spec::{cvs, Cc, LinkerFlavor, Lld, TargetOptions};
pub fn opts() -> TargetOptions {
// We cannot use `-nodefaultlibs` because compiler-rt has to be passed
// as a path since it's not added to linker search path by the default.
// There were attempts to make it behave like libgcc (so one can just use -l<name>)
// but LLVM maintainers rejected it: https://reviews.llvm.org/D51440
- let pre_link_args =
- TargetOptions::link_args(LinkerFlavor::Gcc, &["-nolibc", "--unwindlib=none"]);
+ let pre_link_args = TargetOptions::link_args(
+ LinkerFlavor::Gnu(Cc::Yes, Lld::No),
+ &["-nolibc", "--unwindlib=none"],
+ );
// Order of `late_link_args*` does not matter with LLD.
let late_link_args = TargetOptions::link_args(
- LinkerFlavor::Gcc,
+ LinkerFlavor::Gnu(Cc::Yes, Lld::No),
&["-lmingw32", "-lmingwex", "-lmsvcrt", "-lkernel32", "-luser32"],
);
diff --git a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs
index fa69b919c..f30c33d99 100644
--- a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
+use crate::spec::{Cc, LinkArgs, LinkerFlavor, Lld, TargetOptions};
pub fn opts() -> TargetOptions {
let base = super::windows_gnu_base::opts();
@@ -15,8 +15,9 @@ pub fn opts() -> TargetOptions {
"-lmingwex",
"-lmingw32",
];
- let mut late_link_args = TargetOptions::link_args(LinkerFlavor::Ld, mingw_libs);
- super::add_link_args(&mut late_link_args, LinkerFlavor::Gcc, mingw_libs);
+ let mut late_link_args =
+ TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), mingw_libs);
+ super::add_link_args(&mut late_link_args, LinkerFlavor::Gnu(Cc::Yes, Lld::No), mingw_libs);
// Reset the flags back to empty until the FIXME above is addressed.
let late_link_args_dynamic = LinkArgs::new();
let late_link_args_static = LinkArgs::new();
diff --git a/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs b/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs
index f2573fc2d..8c942c59d 100644
--- a/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs
+++ b/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, TargetOptions};
+use crate::spec::{LinkerFlavor, Lld, TargetOptions};
pub fn opts() -> TargetOptions {
let mut opts = super::windows_msvc_base::opts();
opts.abi = "uwp".into();
opts.vendor = "uwp".into();
- opts.add_pre_link_args(LinkerFlavor::Msvc, &["/APPCONTAINER", "mincore.lib"]);
+ opts.add_pre_link_args(LinkerFlavor::Msvc(Lld::No), &["/APPCONTAINER", "mincore.lib"]);
opts
}
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
index 176c9dd6b..087be1b95 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
@@ -1,5 +1,5 @@
-use crate::spec::TargetOptions;
-use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, StackProbeType, Target};
+use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet};
+use crate::spec::{StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let arch = "x86_64";
@@ -7,10 +7,9 @@ pub fn target() -> Target {
base.cpu = "core2".into();
base.max_atomic_width = Some(128); // core2 support cmpxchg16b
base.frame_pointer = FramePointer::Always;
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+ base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]);
base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove());
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.stack_probes = StackProbeType::X86;
base.supported_sanitizers =
SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD;
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
index 5e64ed0cf..e6143025d 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
@@ -13,8 +13,7 @@ pub fn target() -> Target {
arch: "x86_64".into(),
options: TargetOptions {
max_atomic_width: Some(64),
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- stack_probes: StackProbeType::Call,
+ stack_probes: StackProbeType::X86,
..base
},
}
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 2122bcd37..13259205a 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
@@ -1,11 +1,11 @@
use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let llvm_target = "x86_64-apple-ios13.0-macabi";
let mut base = opts("ios", Arch::X86_64_macabi);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-target", llvm_target]);
+ base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-target", llvm_target]);
Target {
llvm_target: llvm_target.into(),
@@ -15,8 +15,7 @@ pub fn target() -> Target {
arch: "x86_64".into(),
options: TargetOptions {
max_atomic_width: Some(64),
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- stack_probes: StackProbeType::Call,
+ stack_probes: StackProbeType::X86,
..base
},
}
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
index a848c5a0a..3d54da086 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
@@ -10,8 +10,7 @@ pub fn target() -> Target {
arch: "x86_64".into(),
options: TargetOptions {
max_atomic_width: Some(64),
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- stack_probes: StackProbeType::Call,
+ stack_probes: StackProbeType::X86,
..base
},
}
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs
index 4dff3c2f2..e499b1985 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs
@@ -15,8 +15,7 @@ pub fn target() -> Target {
arch: "x86_64".into(),
options: TargetOptions {
max_atomic_width: Some(64),
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- stack_probes: StackProbeType::Call,
+ stack_probes: StackProbeType::X86,
forces_embed_bitcode: true,
// Taken from a clang build on Xcode 11.4.1.
// These arguments are not actually invoked - they just have
diff --git a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
index 9d597ea2e..cba6fda19 100644
--- a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
+++ b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
@@ -1,12 +1,10 @@
use std::borrow::Cow;
-use crate::spec::cvs;
-
-use super::{LinkerFlavor, LldFlavor, Target, TargetOptions};
+use super::{cvs, Cc, LinkerFlavor, Lld, Target, TargetOptions};
pub fn target() -> Target {
let pre_link_args = TargetOptions::link_args(
- LinkerFlavor::Ld,
+ LinkerFlavor::Gnu(Cc::No, Lld::No),
&[
"-e",
"elf_entry",
@@ -61,7 +59,7 @@ pub fn target() -> Target {
env: "sgx".into(),
vendor: "fortanix".into(),
abi: "fortanix".into(),
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
max_atomic_width: Some(64),
cpu: "x86-64".into(),
diff --git a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
index 4f88fc350..532dd6d07 100644
--- a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
@@ -4,8 +4,7 @@ pub fn target() -> Target {
let mut base = super::fuchsia_base::opts();
base.cpu = "x86-64".into();
base.max_atomic_width = Some(64);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.stack_probes = StackProbeType::X86;
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
Target {
diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs
index 6d19cf265..9c9137848 100644
--- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, SanitizerSet, StackProbeType, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::android_base::opts();
@@ -6,9 +6,8 @@ pub fn target() -> Target {
// https://developer.android.com/ndk/guides/abis.html#86-64
base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
+ base.stack_probes = StackProbeType::X86;
Target {
llvm_target: "x86_64-linux-android".into(),
diff --git a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
index 0550b221f..cb62a8173 100644
--- a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
+++ b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
@@ -1,13 +1,12 @@
-use crate::spec::{LinkerFlavor, SanitizerSet, StackProbeType, Target};
+use crate::spec::{Cc, LinkerFlavor, SanitizerSet, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::solaris_base::opts();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+ base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64"]);
base.cpu = "x86-64".into();
base.vendor = "pc".into();
base.max_atomic_width = Some(64);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.stack_probes = StackProbeType::X86;
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
Target {
diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs
index 59a8cffca..37feaa9db 100644
--- a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs
@@ -1,11 +1,14 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target};
pub fn target() -> Target {
let mut base = super::windows_gnu_base::opts();
base.cpu = "x86-64".into();
// Use high-entropy 64 bit address space for ASLR
- base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pep", "--high-entropy-va"]);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-Wl,--high-entropy-va"]);
+ base.add_pre_link_args(
+ LinkerFlavor::Gnu(Cc::No, Lld::No),
+ &["-m", "i386pep", "--high-entropy-va"],
+ );
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64", "-Wl,--high-entropy-va"]);
base.max_atomic_width = Some(64);
base.linker = Some("x86_64-w64-mingw32-gcc".into());
diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs
index d3909b389..039bc2bd2 100644
--- a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs
+++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnullvm.rs
@@ -1,9 +1,9 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target};
pub fn target() -> Target {
let mut base = super::windows_gnullvm_base::opts();
base.cpu = "x86-64".into();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
base.max_atomic_width = Some(64);
base.linker = Some("x86_64-w64-mingw32-clang".into());
diff --git a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
index cbe87589a..0f31ea86b 100644
--- a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
+++ b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
@@ -1,13 +1,12 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{Cc, LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::solaris_base::opts();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+ base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64"]);
base.cpu = "x86-64".into();
base.vendor = "sun".into();
base.max_atomic_width = Some(64);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.stack_probes = StackProbeType::X86;
Target {
llvm_target: "x86_64-pc-solaris".into(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
index 746f64781..67ce3768d 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
@@ -1,12 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::dragonfly_base::opts();
base.cpu = "x86-64".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
+ base.stack_probes = StackProbeType::X86;
Target {
llvm_target: "x86_64-unknown-dragonfly".into(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
index b30784ed6..98988ab35 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
@@ -1,12 +1,11 @@
-use crate::spec::{LinkerFlavor, SanitizerSet, StackProbeType, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::freebsd_base::opts();
base.cpu = "x86-64".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
+ base.stack_probes = StackProbeType::X86;
base.supported_sanitizers =
SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::MEMORY | SanitizerSet::THREAD;
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
index d6d033629..9a7a3b501 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
@@ -1,12 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::haiku_base::opts();
base.cpu = "x86-64".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
+ base.stack_probes = StackProbeType::X86;
// This option is required to build executables on Haiku x86_64
base.position_independent_executables = true;
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
index d31530161..fb1af33f8 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
@@ -5,8 +5,7 @@ pub fn target() -> Target {
base.cpu = "x86-64".into();
base.max_atomic_width = Some(64);
base.features = "+rdrnd,+rdseed".into();
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.stack_probes = StackProbeType::X86;
Target {
llvm_target: "x86_64-unknown-hermit".into(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
index 9f19c3a2b..04a12a7bf 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
@@ -1,8 +1,8 @@
-use crate::spec::{LinkerFlavor, SanitizerSet, Target};
+use crate::spec::{Cc, LinkerFlavor, SanitizerSet, Target};
pub fn target() -> Target {
let mut base = super::illumos_base::opts();
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-std=c99"]);
+ base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64", "-std=c99"]);
base.cpu = "x86-64".into();
base.max_atomic_width = Some(64);
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
index 956be0353..a91ab365b 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
@@ -1,12 +1,11 @@
-use crate::spec::{LinkerFlavor, SanitizerSet, StackProbeType, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts();
base.cpu = "x86-64".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
+ base.stack_probes = StackProbeType::X86;
base.static_position_independent_executables = true;
base.supported_sanitizers = SanitizerSet::ADDRESS
| SanitizerSet::CFI
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
index 140882747..626d5b480 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
@@ -1,13 +1,12 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts();
base.cpu = "x86-64".into();
base.abi = "x32".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-mx32"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-mx32"]);
+ base.stack_probes = StackProbeType::X86;
base.has_thread_local = false;
// BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI
// breaks code gen. See LLVM bug 36743
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
index 87e7784d1..9087dc3df 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
@@ -1,12 +1,11 @@
-use crate::spec::{LinkerFlavor, SanitizerSet, StackProbeType, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::linux_musl_base::opts();
base.cpu = "x86-64".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
+ base.stack_probes = StackProbeType::X86;
base.static_position_independent_executables = true;
base.supported_sanitizers = SanitizerSet::ADDRESS
| SanitizerSet::CFI
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
index d3a67619a..64ae425d8 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
@@ -1,12 +1,11 @@
-use crate::spec::{LinkerFlavor, SanitizerSet, StackProbeType, Target, TargetOptions};
+use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::netbsd_base::opts();
base.cpu = "x86-64".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
+ base.stack_probes = StackProbeType::X86;
base.supported_sanitizers = SanitizerSet::ADDRESS
| SanitizerSet::CFI
| SanitizerSet::LEAK
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs
index b9a345127..e4d33c2b8 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_none.rs
@@ -4,19 +4,18 @@
// `target-cpu` compiler flags to opt-in more hardware-specific
// features.
-use super::{CodeModel, LinkerFlavor, LldFlavor, PanicStrategy};
+use super::{Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy};
use super::{RelroLevel, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let opts = TargetOptions {
cpu: "x86-64".into(),
max_atomic_width: Some(64),
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- stack_probes: StackProbeType::Call,
+ stack_probes: StackProbeType::X86,
position_independent_executables: true,
static_position_independent_executables: true,
relro_level: RelroLevel::Full,
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
features:
"-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float"
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs
index 593345a5f..ebd9636ff 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs
@@ -1,7 +1,7 @@
// This defines the amd64 target for the Linux Kernel. See the linux-kernel-base module for
// generic Linux kernel options.
-use crate::spec::{CodeModel, LinkerFlavor, Target};
+use crate::spec::{Cc, CodeModel, LinkerFlavor, Lld, Target};
pub fn target() -> Target {
let mut base = super::linux_kernel_base::opts();
@@ -10,7 +10,7 @@ pub fn target() -> Target {
base.features =
"-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float".into();
base.code_model = Some(CodeModel::Kernel);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
Target {
// FIXME: Some dispute, the linux-on-clang folks think this should use
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
index f50c6bcee..66b8e2022 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
@@ -1,12 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::openbsd_base::opts();
base.cpu = "x86-64".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
+ base.stack_probes = StackProbeType::X86;
Target {
llvm_target: "x86_64-unknown-openbsd".into(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
index 668ae9054..b47f15cf5 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
@@ -1,12 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::redox_base::opts();
base.cpu = "x86-64".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
+ base.stack_probes = StackProbeType::X86;
Target {
llvm_target: "x86_64-unknown-redox".into(),
diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs
index 76d2013cf..c3eaa6939 100644
--- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs
@@ -1,11 +1,14 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, Target};
pub fn target() -> Target {
let mut base = super::windows_uwp_gnu_base::opts();
base.cpu = "x86-64".into();
// Use high-entropy 64 bit address space for ASLR
- base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pep", "--high-entropy-va"]);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-Wl,--high-entropy-va"]);
+ base.add_pre_link_args(
+ LinkerFlavor::Gnu(Cc::No, Lld::No),
+ &["-m", "i386pep", "--high-entropy-va"],
+ );
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64", "-Wl,--high-entropy-va"]);
base.max_atomic_width = Some(64);
Target {
diff --git a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
index 129897495..365ade6bc 100644
--- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
@@ -1,12 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::vxworks_base::opts();
base.cpu = "x86-64".into();
base.max_atomic_width = Some(64);
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
- // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
- base.stack_probes = StackProbeType::Call;
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
+ base.stack_probes = StackProbeType::X86;
base.disable_redzone = true;
Target {
diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml
index 566f236f2..67613e1a4 100644
--- a/compiler/rustc_trait_selection/Cargo.toml
+++ b/compiler/rustc_trait_selection/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
rustc_parse_format = { path = "../rustc_parse_format" }
diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs
index 36ab8f3bd..61cfeec4b 100644
--- a/compiler/rustc_trait_selection/src/autoderef.rs
+++ b/compiler/rustc_trait_selection/src/autoderef.rs
@@ -25,7 +25,7 @@ struct AutoderefSnapshot<'tcx> {
pub struct Autoderef<'a, 'tcx> {
// Meta infos:
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
span: Span,
overloaded_span: Span,
body_id: hir::HirId,
@@ -94,7 +94,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
impl<'a, 'tcx> Autoderef<'a, 'tcx> {
pub fn new(
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
span: Span,
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index ab0afc545..7f8705824 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -1,11 +1,11 @@
-use rustc_errors::{fluent, ErrorGuaranteed, Handler};
-use rustc_macros::SessionDiagnostic;
-use rustc_middle::ty::{PolyTraitRef, Ty, Unevaluated};
-use rustc_session::{Limit, SessionDiagnostic};
+use rustc_errors::{fluent, ErrorGuaranteed, Handler, IntoDiagnostic};
+use rustc_macros::Diagnostic;
+use rustc_middle::ty::{self, PolyTraitRef, Ty};
+use rustc_session::Limit;
use rustc_span::{Span, Symbol};
-#[derive(SessionDiagnostic)]
-#[diag(trait_selection::dump_vtable_entries)]
+#[derive(Diagnostic)]
+#[diag(trait_selection_dump_vtable_entries)]
pub struct DumpVTableEntries<'a> {
#[primary_span]
pub span: Span,
@@ -13,17 +13,17 @@ pub struct DumpVTableEntries<'a> {
pub entries: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(trait_selection::unable_to_construct_constant_value)]
+#[derive(Diagnostic)]
+#[diag(trait_selection_unable_to_construct_constant_value)]
pub struct UnableToConstructConstantValue<'a> {
#[primary_span]
pub span: Span,
- pub unevaluated: Unevaluated<'a>,
+ pub unevaluated: ty::UnevaluatedConst<'a>,
}
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
#[help]
-#[diag(trait_selection::auto_deref_reached_recursion_limit, code = "E0055")]
+#[diag(trait_selection_auto_deref_reached_recursion_limit, code = "E0055")]
pub struct AutoDerefReachedRecursionLimit<'a> {
#[primary_span]
#[label]
@@ -33,24 +33,24 @@ pub struct AutoDerefReachedRecursionLimit<'a> {
pub crate_name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(trait_selection::empty_on_clause_in_rustc_on_unimplemented, code = "E0232")]
+#[derive(Diagnostic)]
+#[diag(trait_selection_empty_on_clause_in_rustc_on_unimplemented, code = "E0232")]
pub struct EmptyOnClauseInOnUnimplemented {
#[primary_span]
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(trait_selection::invalid_on_clause_in_rustc_on_unimplemented, code = "E0232")]
+#[derive(Diagnostic)]
+#[diag(trait_selection_invalid_on_clause_in_rustc_on_unimplemented, code = "E0232")]
pub struct InvalidOnClauseInOnUnimplemented {
#[primary_span]
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(trait_selection::no_value_in_rustc_on_unimplemented, code = "E0232")]
+#[derive(Diagnostic)]
+#[diag(trait_selection_no_value_in_rustc_on_unimplemented, code = "E0232")]
#[note]
pub struct NoValueInOnUnimplemented {
#[primary_span]
@@ -66,12 +66,12 @@ pub struct NegativePositiveConflict<'a> {
pub positive_impl_span: Result<Span, Symbol>,
}
-impl SessionDiagnostic<'_> for NegativePositiveConflict<'_> {
+impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> {
fn into_diagnostic(
self,
handler: &Handler,
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
- let mut diag = handler.struct_err(fluent::trait_selection::negative_positive_conflict);
+ let mut diag = handler.struct_err(fluent::trait_selection_negative_positive_conflict);
diag.set_arg("trait_desc", self.trait_desc);
diag.set_arg(
"self_desc",
@@ -81,19 +81,19 @@ impl SessionDiagnostic<'_> for NegativePositiveConflict<'_> {
diag.code(rustc_errors::error_code!(E0751));
match self.negative_impl_span {
Ok(span) => {
- diag.span_label(span, fluent::trait_selection::negative_implementation_here);
+ diag.span_label(span, fluent::negative_implementation_here);
}
Err(cname) => {
- diag.note(fluent::trait_selection::negative_implementation_in_crate);
+ diag.note(fluent::negative_implementation_in_crate);
diag.set_arg("negative_impl_cname", cname.to_string());
}
}
match self.positive_impl_span {
Ok(span) => {
- diag.span_label(span, fluent::trait_selection::positive_implementation_here);
+ diag.span_label(span, fluent::positive_implementation_here);
}
Err(cname) => {
- diag.note(fluent::trait_selection::positive_implementation_in_crate);
+ diag.note(fluent::positive_implementation_in_crate);
diag.set_arg("positive_impl_cname", cname.to_string());
}
}
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index ba403ab2d..a335f8e06 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -59,7 +59,7 @@ pub trait InferCtxtExt<'tcx> {
param_env: ty::ParamEnv<'tcx>,
) -> traits::EvaluationResult;
}
-impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
fn type_is_copy_modulo_regions(
&self,
param_env: ty::ParamEnv<'tcx>,
@@ -69,7 +69,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
let ty = self.resolve_vars_if_possible(ty);
if !(param_env, ty).needs_infer() {
- return ty.is_copy_modulo_regions(self.tcx.at(span), param_env);
+ return ty.is_copy_modulo_regions(self.tcx, param_env);
}
let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None);
@@ -142,7 +142,7 @@ pub trait InferCtxtBuilderExt<'tcx> {
fn enter_canonical_trait_query<K, R>(
&mut self,
canonical_key: &Canonical<'tcx, K>,
- operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
+ operation: impl FnOnce(&InferCtxt<'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
where
K: TypeFoldable<'tcx>,
@@ -170,25 +170,17 @@ impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> {
fn enter_canonical_trait_query<K, R>(
&mut self,
canonical_key: &Canonical<'tcx, K>,
- operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
+ operation: impl FnOnce(&InferCtxt<'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
where
K: TypeFoldable<'tcx>,
R: Debug + TypeFoldable<'tcx>,
Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
{
- self.enter_with_canonical(
- DUMMY_SP,
- canonical_key,
- |ref infcx, key, canonical_inference_vars| {
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
- let value = operation(infcx, &mut *fulfill_cx, key)?;
- infcx.make_canonicalized_query_response(
- canonical_inference_vars,
- value,
- &mut *fulfill_cx,
- )
- },
- )
+ let (ref infcx, key, canonical_inference_vars) =
+ self.build_with_canonical(DUMMY_SP, canonical_key);
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+ let value = operation(infcx, &mut *fulfill_cx, key)?;
+ infcx.make_canonicalized_query_response(canonical_inference_vars, value, &mut *fulfill_cx)
}
}
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index d35f74974..5d52aa075 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -16,9 +16,7 @@
#![feature(control_flow_enum)]
#![feature(drain_filter)]
#![feature(hash_drain_filter)]
-#![cfg_attr(bootstrap, feature(label_break_value))]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(if_let_guard)]
#![feature(never_type)]
#![feature(type_alias_impl_trait)]
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index bcdfa4f12..ed34ab95a 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -10,7 +10,7 @@ use crate::traits::project::ProjectAndUnifyResult;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{Region, RegionVid};
+use rustc_middle::ty::{PolyTraitRef, Region, RegionVid};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -66,13 +66,13 @@ impl<'tcx> AutoTraitFinder<'tcx> {
/// struct Foo<T> { data: Box<T> }
/// ```
///
- /// then this might return that Foo<T>: Send if T: Send (encoded in the AutoTraitResult type).
- /// The analysis attempts to account for custom impls as well as other complex cases. This
- /// result is intended for use by rustdoc and other such consumers.
+ /// then this might return that `Foo<T>: Send` if `T: Send` (encoded in the AutoTraitResult
+ /// type). The analysis attempts to account for custom impls as well as other complex cases.
+ /// This result is intended for use by rustdoc and other such consumers.
///
/// (Note that due to the coinductive nature of Send, the full and correct result is actually
/// quite simple to generate. That is, when a type has no custom impl, it is Send iff its field
- /// types are all Send. So, in our example, we might have that Foo<T>: Send if Box<T>: Send.
+ /// types are all Send. So, in our example, we might have that `Foo<T>: Send` if `Box<T>: Send`.
/// But this is often not the best way to present to the user.)
///
/// Warning: The API should be considered highly unstable, and it may be refactored or removed
@@ -90,143 +90,105 @@ impl<'tcx> AutoTraitFinder<'tcx> {
let trait_pred = ty::Binder::dummy(trait_ref);
- let bail_out = tcx.infer_ctxt().enter(|infcx| {
- let mut selcx = SelectionContext::new(&infcx);
- let result = selcx.select(&Obligation::new(
- ObligationCause::dummy(),
- orig_env,
- trait_pred.to_poly_trait_predicate(),
- ));
-
- match result {
- Ok(Some(ImplSource::UserDefined(_))) => {
- debug!(
- "find_auto_trait_generics({:?}): \
- manual impl found, bailing out",
- trait_ref
- );
- return true;
- }
- _ => {}
+ let infcx = tcx.infer_ctxt().build();
+ let mut selcx = SelectionContext::new(&infcx);
+ for f in [
+ PolyTraitRef::to_poly_trait_predicate,
+ PolyTraitRef::to_poly_trait_predicate_negative_polarity,
+ ] {
+ let result =
+ selcx.select(&Obligation::new(ObligationCause::dummy(), orig_env, f(&trait_pred)));
+ if let Ok(Some(ImplSource::UserDefined(_))) = result {
+ debug!(
+ "find_auto_trait_generics({:?}): \
+ manual impl found, bailing out",
+ trait_ref
+ );
+ // If an explicit impl exists, it always takes priority over an auto impl
+ return AutoTraitResult::ExplicitImpl;
}
-
- let result = selcx.select(&Obligation::new(
- ObligationCause::dummy(),
- orig_env,
- trait_pred.to_poly_trait_predicate_negative_polarity(),
- ));
-
- match result {
- Ok(Some(ImplSource::UserDefined(_))) => {
- debug!(
- "find_auto_trait_generics({:?}): \
- manual impl found, bailing out",
- trait_ref
- );
- true
- }
- _ => false,
- }
- });
-
- // If an explicit impl exists, it always takes priority over an auto impl
- if bail_out {
- return AutoTraitResult::ExplicitImpl;
}
- tcx.infer_ctxt().enter(|infcx| {
- let mut fresh_preds = FxHashSet::default();
+ let infcx = tcx.infer_ctxt().build();
+ let mut fresh_preds = FxHashSet::default();
+
+ // Due to the way projections are handled by SelectionContext, we need to run
+ // evaluate_predicates twice: once on the original param env, and once on the result of
+ // the first evaluate_predicates call.
+ //
+ // The problem is this: most of rustc, including SelectionContext and traits::project,
+ // are designed to work with a concrete usage of a type (e.g., Vec<u8>
+ // fn<T>() { Vec<T> }. This information will generally never change - given
+ // the 'T' in fn<T>() { ... }, we'll never know anything else about 'T'.
+ // If we're unable to prove that 'T' implements a particular trait, we're done -
+ // there's nothing left to do but error out.
+ //
+ // However, synthesizing an auto trait impl works differently. Here, we start out with
+ // a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing
+ // with - and progressively discover the conditions we need to fulfill for it to
+ // implement a certain auto trait. This ends up breaking two assumptions made by trait
+ // selection and projection:
+ //
+ // * We can always cache the result of a particular trait selection for the lifetime of
+ // an InfCtxt
+ // * Given a projection bound such as '<T as SomeTrait>::SomeItem = K', if 'T:
+ // SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K'
+ //
+ // We fix the first assumption by manually clearing out all of the InferCtxt's caches
+ // in between calls to SelectionContext.select. This allows us to keep all of the
+ // intermediate types we create bound to the 'tcx lifetime, rather than needing to lift
+ // them between calls.
+ //
+ // We fix the second assumption by reprocessing the result of our first call to
+ // evaluate_predicates. Using the example of '<T as SomeTrait>::SomeItem = K', our first
+ // pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass,
+ // traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing
+ // SelectionContext to return it back to us.
+
+ let Some((new_env, user_env)) = self.evaluate_predicates(
+ &infcx,
+ trait_did,
+ ty,
+ orig_env,
+ orig_env,
+ &mut fresh_preds,
+ false,
+ ) else {
+ return AutoTraitResult::NegativeImpl;
+ };
+
+ let (full_env, full_user_env) = self
+ .evaluate_predicates(&infcx, trait_did, ty, new_env, user_env, &mut fresh_preds, true)
+ .unwrap_or_else(|| {
+ panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env)
+ });
- // Due to the way projections are handled by SelectionContext, we need to run
- // evaluate_predicates twice: once on the original param env, and once on the result of
- // the first evaluate_predicates call.
- //
- // The problem is this: most of rustc, including SelectionContext and traits::project,
- // are designed to work with a concrete usage of a type (e.g., Vec<u8>
- // fn<T>() { Vec<T> }. This information will generally never change - given
- // the 'T' in fn<T>() { ... }, we'll never know anything else about 'T'.
- // If we're unable to prove that 'T' implements a particular trait, we're done -
- // there's nothing left to do but error out.
- //
- // However, synthesizing an auto trait impl works differently. Here, we start out with
- // a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing
- // with - and progressively discover the conditions we need to fulfill for it to
- // implement a certain auto trait. This ends up breaking two assumptions made by trait
- // selection and projection:
- //
- // * We can always cache the result of a particular trait selection for the lifetime of
- // an InfCtxt
- // * Given a projection bound such as '<T as SomeTrait>::SomeItem = K', if 'T:
- // SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K'
- //
- // We fix the first assumption by manually clearing out all of the InferCtxt's caches
- // in between calls to SelectionContext.select. This allows us to keep all of the
- // intermediate types we create bound to the 'tcx lifetime, rather than needing to lift
- // them between calls.
- //
- // We fix the second assumption by reprocessing the result of our first call to
- // evaluate_predicates. Using the example of '<T as SomeTrait>::SomeItem = K', our first
- // pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass,
- // traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing
- // SelectionContext to return it back to us.
-
- let Some((new_env, user_env)) = self.evaluate_predicates(
- &infcx,
- trait_did,
- ty,
- orig_env,
- orig_env,
- &mut fresh_preds,
- false,
- ) else {
- return AutoTraitResult::NegativeImpl;
- };
-
- let (full_env, full_user_env) = self
- .evaluate_predicates(
- &infcx,
- trait_did,
- ty,
- new_env,
- user_env,
- &mut fresh_preds,
- true,
- )
- .unwrap_or_else(|| {
- panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env)
- });
-
- debug!(
- "find_auto_trait_generics({:?}): fulfilling \
- with {:?}",
- trait_ref, full_env
- );
- infcx.clear_caches();
-
- // At this point, we already have all of the bounds we need. FulfillmentContext is used
- // to store all of the necessary region/lifetime bounds in the InferContext, as well as
- // an additional sanity check.
- let errors =
- super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
- if !errors.is_empty() {
- panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
- }
+ debug!(
+ "find_auto_trait_generics({:?}): fulfilling \
+ with {:?}",
+ trait_ref, full_env
+ );
+ infcx.clear_caches();
+
+ // At this point, we already have all of the bounds we need. FulfillmentContext is used
+ // to store all of the necessary region/lifetime bounds in the InferContext, as well as
+ // an additional sanity check.
+ let errors =
+ super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
+ if !errors.is_empty() {
+ panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
+ }
- infcx.process_registered_region_obligations(&Default::default(), full_env);
+ infcx.process_registered_region_obligations(&Default::default(), full_env);
- let region_data = infcx
- .inner
- .borrow_mut()
- .unwrap_region_constraints()
- .region_constraint_data()
- .clone();
+ let region_data =
+ infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone();
- let vid_to_region = self.map_vid_to_region(&region_data);
+ let vid_to_region = self.map_vid_to_region(&region_data);
- let info = AutoTraitInfo { full_user_env, region_data, vid_to_region };
+ let info = AutoTraitInfo { full_user_env, region_data, vid_to_region };
- AutoTraitResult::PositiveImpl(auto_trait_callback(info))
- })
+ AutoTraitResult::PositiveImpl(auto_trait_callback(info))
}
}
@@ -272,7 +234,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
/// user.
fn evaluate_predicates(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
trait_did: DefId,
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -834,7 +796,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
let reported =
tcx.sess.emit_err(UnableToConstructConstantValue {
span: tcx.def_span(def_id),
- unevaluated: unevaluated.expand(),
+ unevaluated: unevaluated,
});
Err(ErrorHandled::Reported(reported))
}
@@ -877,7 +839,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
pub fn clean_pred(
&self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
p: ty::Predicate<'tcx>,
) -> ty::Predicate<'tcx> {
infcx.freshen(p)
diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
index 9ef7ac9a8..81e1d6449 100644
--- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
@@ -28,7 +28,7 @@ impl FulfillmentContext<'_> {
impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn normalize_projection_type(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
_param_env: ty::ParamEnv<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
_cause: ObligationCause<'tcx>,
@@ -38,7 +38,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn register_predicate_obligation(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
obligation: PredicateObligation<'tcx>,
) {
assert!(!infcx.is_in_snapshot());
@@ -49,7 +49,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
self.obligations.insert(obligation);
}
- fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
{
let errors = self.select_where_possible(infcx);
@@ -71,10 +71,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
.collect()
}
- fn select_where_possible(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Vec<FulfillmentError<'tcx>> {
+ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
assert!(!infcx.is_in_snapshot());
let mut errors = Vec::new();
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index 08adbcbd4..8a62bf015 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -4,10 +4,12 @@
// general routines.
use crate::infer::{DefiningAnchor, TyCtxtInferExt};
+use crate::traits::error_reporting::TypeErrCtxtExt;
use crate::traits::{
ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt,
Unimplemented,
};
+use rustc_infer::traits::FulfillmentErrorCode;
use rustc_middle::traits::CodegenObligationError;
use rustc_middle::ty::{self, TyCtxt};
@@ -27,52 +29,61 @@ pub fn codegen_select_candidate<'tcx>(
// Do the initial selection for the obligation. This yields the
// shallow result we are looking for -- that is, what specific impl.
- let mut infcx_builder =
- tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble);
- infcx_builder.enter(|infcx| {
- //~^ HACK `Bubble` is required for
- // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs
- let mut selcx = SelectionContext::new(&infcx);
+ let infcx = tcx
+ .infer_ctxt()
+ .ignoring_regions()
+ .with_opaque_type_inference(DefiningAnchor::Bubble)
+ .build();
+ //~^ HACK `Bubble` is required for
+ // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs
+ let mut selcx = SelectionContext::new(&infcx);
- let obligation_cause = ObligationCause::dummy();
- let obligation =
- Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());
+ let obligation_cause = ObligationCause::dummy();
+ let obligation =
+ Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());
- let selection = match selcx.select(&obligation) {
- Ok(Some(selection)) => selection,
- Ok(None) => return Err(CodegenObligationError::Ambiguity),
- Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented),
- Err(e) => {
- bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
- }
- };
+ let selection = match selcx.select(&obligation) {
+ Ok(Some(selection)) => selection,
+ Ok(None) => return Err(CodegenObligationError::Ambiguity),
+ Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented),
+ Err(e) => {
+ bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
+ }
+ };
- debug!(?selection);
+ debug!(?selection);
- // Currently, we use a fulfillment context to completely resolve
- // all nested obligations. This is because they can inform the
- // inference of the impl's type parameters.
- let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
- let impl_source = selection.map(|predicate| {
- fulfill_cx.register_predicate_obligation(&infcx, predicate);
- });
+ // Currently, we use a fulfillment context to completely resolve
+ // all nested obligations. This is because they can inform the
+ // inference of the impl's type parameters.
+ let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
+ let impl_source = selection.map(|predicate| {
+ fulfill_cx.register_predicate_obligation(&infcx, predicate);
+ });
- // In principle, we only need to do this so long as `impl_source`
- // contains unbound type parameters. It could be a slight
- // optimization to stop iterating early.
- let errors = fulfill_cx.select_all_or_error(&infcx);
- if !errors.is_empty() {
- return Err(CodegenObligationError::FulfillmentError);
+ // In principle, we only need to do this so long as `impl_source`
+ // contains unbound type parameters. It could be a slight
+ // optimization to stop iterating early.
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ // `rustc_monomorphize::collector` assumes there are no type errors.
+ // Cycle errors are the only post-monomorphization errors possible; emit them now so
+ // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization.
+ for err in errors {
+ if let FulfillmentErrorCode::CodeCycle(cycle) = err.code {
+ infcx.err_ctxt().report_overflow_error_cycle(&cycle);
+ }
}
+ return Err(CodegenObligationError::FulfillmentError);
+ }
- let impl_source = infcx.resolve_vars_if_possible(impl_source);
- let impl_source = infcx.tcx.erase_regions(impl_source);
+ let impl_source = infcx.resolve_vars_if_possible(impl_source);
+ let impl_source = infcx.tcx.erase_regions(impl_source);
- // Opaque types may have gotten their hidden types constrained, but we can ignore them safely
- // as they will get constrained elsewhere, too.
- // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass
- let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+ // Opaque types may have gotten their hidden types constrained, but we can ignore them safely
+ // as they will get constrained elsewhere, too.
+ // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass
+ let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
- Ok(&*tcx.arena.alloc(impl_source))
- })
+ Ok(&*tcx.arena.alloc(impl_source))
}
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 292787d4d..8aab75490 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -22,7 +22,6 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::util;
use rustc_middle::traits::specialization_graph::OverlapMode;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
-use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitor};
use rustc_span::symbol::sym;
@@ -61,23 +60,17 @@ pub fn add_placeholder_note(err: &mut Diagnostic) {
);
}
-/// If there are types that satisfy both impls, invokes `on_overlap`
+/// If there are types that satisfy both impls, returns `Some`
/// with a suitably-freshened `ImplHeader` with those types
-/// substituted. Otherwise, invokes `no_overlap`.
-#[instrument(skip(tcx, skip_leak_check, on_overlap, no_overlap), level = "debug")]
-pub fn overlapping_impls<F1, F2, R>(
+/// substituted. Otherwise, returns `None`.
+#[instrument(skip(tcx, skip_leak_check), level = "debug")]
+pub fn overlapping_impls(
tcx: TyCtxt<'_>,
impl1_def_id: DefId,
impl2_def_id: DefId,
skip_leak_check: SkipLeakCheck,
overlap_mode: OverlapMode,
- on_overlap: F1,
- no_overlap: F2,
-) -> R
-where
- F1: FnOnce(OverlapResult<'_>) -> R,
- F2: FnOnce() -> R,
-{
+) -> Option<OverlapResult<'_>> {
// Before doing expensive operations like entering an inference context, do
// a quick check via fast_reject to tell if the impl headers could possibly
// unify.
@@ -98,28 +91,24 @@ where
if !may_overlap {
// Some types involved are definitely different, so the impls couldn't possibly overlap.
debug!("overlapping_impls: fast_reject early-exit");
- return no_overlap();
+ return None;
}
- let overlaps = tcx.infer_ctxt().enter(|infcx| {
- let selcx = &mut SelectionContext::intercrate(&infcx);
- overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some()
- });
-
+ let infcx = tcx.infer_ctxt().build();
+ let selcx = &mut SelectionContext::intercrate(&infcx);
+ let overlaps =
+ overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some();
if !overlaps {
- return no_overlap();
+ return None;
}
// In the case where we detect an error, run the check again, but
// this time tracking intercrate ambiguity causes for better
// diagnostics. (These take time and can lead to false errors.)
- tcx.infer_ctxt().enter(|infcx| {
- let selcx = &mut SelectionContext::intercrate(&infcx);
- selcx.enable_tracking_intercrate_ambiguity_causes();
- on_overlap(
- overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap(),
- )
- })
+ let infcx = tcx.infer_ctxt().build();
+ let selcx = &mut SelectionContext::intercrate(&infcx);
+ selcx.enable_tracking_intercrate_ambiguity_causes();
+ Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())
}
fn with_fresh_ty_vars<'cx, 'tcx>(
@@ -168,7 +157,7 @@ fn overlap_within_probe<'cx, 'tcx>(
impl1_def_id: DefId,
impl2_def_id: DefId,
overlap_mode: OverlapMode,
- snapshot: &CombinedSnapshot<'_, 'tcx>,
+ snapshot: &CombinedSnapshot<'tcx>,
) -> Option<OverlapResult<'tcx>> {
let infcx = selcx.infcx();
@@ -198,7 +187,7 @@ fn overlap_within_probe<'cx, 'tcx>(
}
}
- // We disable the leak when when creating the `snapshot` by using
+ // We disable the leak when creating the `snapshot` by using
// `infcx.probe_maybe_disable_leak_check`.
if infcx.leak_check(true, snapshot).is_err() {
debug!("overlap: leak check failed");
@@ -299,37 +288,36 @@ fn negative_impl<'cx, 'tcx>(
let tcx = selcx.infcx().tcx;
// Create an infcx, taking the predicates of impl1 as assumptions:
- tcx.infer_ctxt().enter(|infcx| {
- // create a parameter environment corresponding to a (placeholder) instantiation of impl1
- let impl_env = tcx.param_env(impl1_def_id);
- let subject1 = match traits::fully_normalize(
- &infcx,
- ObligationCause::dummy(),
- impl_env,
- tcx.impl_subject(impl1_def_id),
- ) {
- Ok(s) => s,
- Err(err) => {
- tcx.sess.delay_span_bug(
- tcx.def_span(impl1_def_id),
- format!("failed to fully normalize {:?}: {:?}", impl1_def_id, err),
- );
- return false;
- }
- };
+ let infcx = tcx.infer_ctxt().build();
+ // create a parameter environment corresponding to a (placeholder) instantiation of impl1
+ let impl_env = tcx.param_env(impl1_def_id);
+ let subject1 = match traits::fully_normalize(
+ &infcx,
+ ObligationCause::dummy(),
+ impl_env,
+ tcx.impl_subject(impl1_def_id),
+ ) {
+ Ok(s) => s,
+ Err(err) => {
+ tcx.sess.delay_span_bug(
+ tcx.def_span(impl1_def_id),
+ format!("failed to fully normalize {:?}: {:?}", impl1_def_id, err),
+ );
+ return false;
+ }
+ };
- // Attempt to prove that impl2 applies, given all of the above.
- 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);
+ // Attempt to prove that impl2 applies, given all of the above.
+ 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);
- !equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
- })
+ !equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
}
-fn equate<'cx, 'tcx>(
- infcx: &InferCtxt<'cx, 'tcx>,
+fn equate<'tcx>(
+ infcx: &InferCtxt<'tcx>,
impl_env: ty::ParamEnv<'tcx>,
subject1: ImplSubject<'tcx>,
subject2: ImplSubject<'tcx>,
@@ -380,8 +368,8 @@ fn negative_impl_exists<'cx, 'tcx>(
}
#[instrument(level = "debug", skip(infcx))]
-fn resolve_negative_obligation<'cx, 'tcx>(
- infcx: InferCtxt<'cx, 'tcx>,
+fn resolve_negative_obligation<'tcx>(
+ infcx: InferCtxt<'tcx>,
o: &PredicateObligation<'tcx>,
body_def_id: DefId,
) -> bool {
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 5a213987e..84038625f 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -9,14 +9,12 @@
//! `thir_abstract_const` which can then be checked for structural equality with other
//! generic constants mentioned in the `caller_bounds` of the current environment.
use rustc_errors::ErrorGuaranteed;
-use rustc_hir::def::DefKind;
use rustc_infer::infer::InferCtxt;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::abstract_const::{
walk_abstract_const, AbstractConst, FailureKind, Node, NotConstEvaluatable,
};
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
-use rustc_session::lint;
use rustc_span::Span;
use std::iter;
@@ -101,7 +99,7 @@ impl<'tcx> ConstUnifyCtxt<'tcx> {
a_uv == b_uv
}
// FIXME(generic_const_exprs): We may want to either actually try
- // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
+ // to evaluate `a_ct` and `b_ct` if they are fully concrete or something like
// this, for now we just return false here.
_ => false,
}
@@ -138,7 +136,7 @@ impl<'tcx> ConstUnifyCtxt<'tcx> {
#[instrument(skip(tcx), level = "debug")]
pub fn try_unify_abstract_consts<'tcx>(
tcx: TyCtxt<'tcx>,
- (a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>),
+ (a, b): (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>),
param_env: ty::ParamEnv<'tcx>,
) -> bool {
(|| {
@@ -159,13 +157,22 @@ pub fn try_unify_abstract_consts<'tcx>(
/// Check if a given constant can be evaluated.
#[instrument(skip(infcx), level = "debug")]
-pub fn is_const_evaluatable<'cx, 'tcx>(
- infcx: &InferCtxt<'cx, 'tcx>,
- uv: ty::Unevaluated<'tcx, ()>,
+pub fn is_const_evaluatable<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ ct: ty::Const<'tcx>,
param_env: ty::ParamEnv<'tcx>,
span: Span,
) -> Result<(), NotConstEvaluatable> {
let tcx = infcx.tcx;
+ let uv = match ct.kind() {
+ ty::ConstKind::Unevaluated(uv) => uv,
+ ty::ConstKind::Param(_)
+ | ty::ConstKind::Bound(_, _)
+ | ty::ConstKind::Placeholder(_)
+ | ty::ConstKind::Value(_)
+ | ty::ConstKind::Error(_) => return Ok(()),
+ ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer),
+ };
if tcx.features().generic_const_exprs {
if let Some(ct) = AbstractConst::new(tcx, uv)? {
@@ -235,39 +242,25 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
.emit()
}
- Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() {
- NotConstEvaluatable::MentionsInfer
- } else if uv.has_param_types_or_consts() {
- NotConstEvaluatable::MentionsParam
- } else {
- let guar = infcx.tcx.sess.delay_span_bug(span, format!("Missing value for constant, but no error reported?"));
- NotConstEvaluatable::Error(guar)
- }),
+ Err(ErrorHandled::TooGeneric) => {
+ let err = if uv.has_non_region_infer() {
+ NotConstEvaluatable::MentionsInfer
+ } else if uv.has_non_region_param() {
+ NotConstEvaluatable::MentionsParam
+ } else {
+ let guar = infcx.tcx.sess.delay_span_bug(span, format!("Missing value for constant, but no error reported?"));
+ NotConstEvaluatable::Error(guar)
+ };
+
+ Err(err)
+ },
Err(ErrorHandled::Linted) => {
let reported =
infcx.tcx.sess.delay_span_bug(span, "constant in type had error reported as lint");
Err(NotConstEvaluatable::Error(reported))
}
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
- Ok(_) => {
- if uv.substs.has_param_types_or_consts() {
- assert!(matches!(infcx.tcx.def_kind(uv.def.did), DefKind::AnonConst));
- let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
-
- if mir_body.is_polymorphic {
- let Some(local_def_id) = uv.def.did.as_local() else { return Ok(()) };
- tcx.struct_span_lint_hir(
- lint::builtin::CONST_EVALUATABLE_UNCHECKED,
- tcx.hir().local_def_id_to_hir_id(local_def_id),
- span,
- |err| {
- err.build("cannot use constants which depend on generic parameters in types").emit();
- })
- }
- }
-
- Ok(())
- },
+ Ok(_) => Ok(()),
}
}
}
@@ -281,7 +274,7 @@ fn satisfied_from_param_env<'tcx>(
for pred in param_env.caller_bounds() {
match pred.kind().skip_binder() {
ty::PredicateKind::ConstEvaluatable(uv) => {
- if let Some(b_ct) = AbstractConst::new(tcx, uv)? {
+ if let Some(b_ct) = AbstractConst::from_const(tcx, uv)? {
let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env };
// Try to unify with each subtree in the AbstractConst to allow for
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index dba4d4f69..e0c8deec9 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -41,16 +41,16 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
/// Used if you want to have pleasant experience when dealing
/// with obligations outside of hir or mir typeck.
pub struct ObligationCtxt<'a, 'tcx> {
- pub infcx: &'a InferCtxt<'a, 'tcx>,
+ pub infcx: &'a InferCtxt<'tcx>,
engine: RefCell<Box<dyn TraitEngine<'tcx>>>,
}
impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
- pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
+ pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new(infcx.tcx)) }
}
- pub fn new_in_snapshot(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
+ pub fn new_in_snapshot(infcx: &'a InferCtxt<'tcx>) -> Self {
Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new_in_snapshot(infcx.tcx)) }
}
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 efdb1ace1..1217d264a 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -2,10 +2,10 @@ pub mod on_unimplemented;
pub mod suggestions;
use super::{
- EvaluationResult, FulfillmentContext, FulfillmentError, FulfillmentErrorCode,
- MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
- OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, Overflow,
- PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe,
+ FulfillmentContext, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
+ Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedDirective,
+ OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, PredicateObligation,
+ SelectionContext, SelectionError, TraitNotObjectSafe,
};
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
@@ -22,6 +22,7 @@ use rustc_hir::intravisit::Visitor;
use rustc_hir::GenericParam;
use rustc_hir::Item;
use rustc_hir::Node;
+use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::TypeTrace;
use rustc_infer::traits::TraitEngine;
use rustc_middle::traits::select::OverflowError;
@@ -32,6 +33,8 @@ use rustc_middle::ty::{
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
TypeVisitable,
};
+use rustc_session::Limit;
+use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::symbol::{kw, sym};
use rustc_span::{ExpnKind, Span, DUMMY_SP};
use std::fmt;
@@ -41,8 +44,8 @@ use std::ops::ControlFlow;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::query::normalize::AtExt as _;
use crate::traits::specialize::to_pretty_impl_header;
-use on_unimplemented::InferCtxtExt as _;
-use suggestions::InferCtxtExt as _;
+use on_unimplemented::TypeErrCtxtExt as _;
+use suggestions::TypeErrCtxtExt as _;
pub use rustc_infer::traits::error_reporting::*;
@@ -63,6 +66,37 @@ pub struct ImplCandidate<'tcx> {
}
pub trait InferCtxtExt<'tcx> {
+ /// Given some node representing a fn-like thing in the HIR map,
+ /// returns a span and `ArgKind` information that describes the
+ /// arguments it expects. This can be supplied to
+ /// `report_arg_count_mismatch`.
+ fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)>;
+
+ /// Reports an error when the number of arguments needed by a
+ /// trait match doesn't match the number that the expression
+ /// provides.
+ fn report_arg_count_mismatch(
+ &self,
+ span: Span,
+ found_span: Option<Span>,
+ expected_args: Vec<ArgKind>,
+ found_args: Vec<ArgKind>,
+ is_closure: bool,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+
+ /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
+ /// in that order, and returns the generic type corresponding to the
+ /// argument of that trait (corresponding to the closure arguments).
+ fn type_implements_fn_trait(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: ty::Binder<'tcx, Ty<'tcx>>,
+ constness: ty::BoundConstness,
+ polarity: ty::ImplPolarity,
+ ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>;
+}
+
+pub trait TypeErrCtxtExt<'tcx> {
fn report_fulfillment_errors(
&self,
errors: &[FulfillmentError<'tcx>],
@@ -78,6 +112,8 @@ pub trait InferCtxtExt<'tcx> {
where
T: fmt::Display + TypeFoldable<'tcx>;
+ fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
+
fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !;
/// The `root_obligation` parameter should be the `root_obligation` field
@@ -90,12 +126,71 @@ pub trait InferCtxtExt<'tcx> {
error: &SelectionError<'tcx>,
fallback_has_occurred: bool,
);
+}
+impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
/// Given some node representing a fn-like thing in the HIR map,
/// returns a span and `ArgKind` information that describes the
/// arguments it expects. This can be supplied to
/// `report_arg_count_mismatch`.
- fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)>;
+ fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)> {
+ let sm = self.tcx.sess.source_map();
+ let hir = self.tcx.hir();
+ Some(match node {
+ Node::Expr(&hir::Expr {
+ kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }),
+ ..
+ }) => (
+ fn_decl_span,
+ hir.body(body)
+ .params
+ .iter()
+ .map(|arg| {
+ if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } =
+ *arg.pat
+ {
+ Some(ArgKind::Tuple(
+ Some(span),
+ args.iter()
+ .map(|pat| {
+ sm.span_to_snippet(pat.span)
+ .ok()
+ .map(|snippet| (snippet, "_".to_owned()))
+ })
+ .collect::<Option<Vec<_>>>()?,
+ ))
+ } else {
+ let name = sm.span_to_snippet(arg.pat.span).ok()?;
+ Some(ArgKind::Arg(name, "_".to_owned()))
+ }
+ })
+ .collect::<Option<Vec<ArgKind>>>()?,
+ ),
+ Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, ..), .. })
+ | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. })
+ | Node::TraitItem(&hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(ref sig, _), ..
+ }) => (
+ sig.span,
+ sig.decl
+ .inputs
+ .iter()
+ .map(|arg| match arg.kind {
+ hir::TyKind::Tup(ref tys) => ArgKind::Tuple(
+ Some(arg.span),
+ vec![("_".to_owned(), "_".to_owned()); tys.len()],
+ ),
+ _ => ArgKind::empty(),
+ })
+ .collect::<Vec<ArgKind>>(),
+ ),
+ Node::Ctor(ref variant_data) => {
+ let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id));
+ (span, vec![ArgKind::empty(); variant_data.fields().len()])
+ }
+ _ => panic!("non-FnLike node found: {:?}", node),
+ })
+ }
/// Reports an error when the number of arguments needed by a
/// trait match doesn't match the number that the expression
@@ -107,21 +202,175 @@ pub trait InferCtxtExt<'tcx> {
expected_args: Vec<ArgKind>,
found_args: Vec<ArgKind>,
is_closure: bool,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ let kind = if is_closure { "closure" } else { "function" };
+
+ let args_str = |arguments: &[ArgKind], other: &[ArgKind]| {
+ let arg_length = arguments.len();
+ let distinct = matches!(other, &[ArgKind::Tuple(..)]);
+ match (arg_length, arguments.get(0)) {
+ (1, Some(&ArgKind::Tuple(_, ref fields))) => {
+ format!("a single {}-tuple as argument", fields.len())
+ }
+ _ => format!(
+ "{} {}argument{}",
+ arg_length,
+ if distinct && arg_length > 1 { "distinct " } else { "" },
+ pluralize!(arg_length)
+ ),
+ }
+ };
+
+ let expected_str = args_str(&expected_args, &found_args);
+ let found_str = args_str(&found_args, &expected_args);
+
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0593,
+ "{} is expected to take {}, but it takes {}",
+ kind,
+ expected_str,
+ found_str,
+ );
+
+ err.span_label(span, format!("expected {} that takes {}", kind, expected_str));
+
+ if let Some(found_span) = found_span {
+ err.span_label(found_span, format!("takes {}", found_str));
+
+ // move |_| { ... }
+ // ^^^^^^^^-- def_span
+ //
+ // move |_| { ... }
+ // ^^^^^-- prefix
+ let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span);
+ // move |_| { ... }
+ // ^^^-- pipe_span
+ let pipe_span =
+ if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span };
+
+ // Suggest to take and ignore the arguments with expected_args_length `_`s if
+ // found arguments is empty (assume the user just wants to ignore args in this case).
+ // For example, if `expected_args_length` is 2, suggest `|_, _|`.
+ if found_args.is_empty() && is_closure {
+ let underscores = vec!["_"; expected_args.len()].join(", ");
+ err.span_suggestion_verbose(
+ pipe_span,
+ &format!(
+ "consider changing the closure to take and ignore the expected argument{}",
+ pluralize!(expected_args.len())
+ ),
+ format!("|{}|", underscores),
+ Applicability::MachineApplicable,
+ );
+ }
+
+ if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] {
+ if fields.len() == expected_args.len() {
+ let sugg = fields
+ .iter()
+ .map(|(name, _)| name.to_owned())
+ .collect::<Vec<String>>()
+ .join(", ");
+ err.span_suggestion_verbose(
+ found_span,
+ "change the closure to take multiple arguments instead of a single tuple",
+ format!("|{}|", sugg),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..]
+ && fields.len() == found_args.len()
+ && is_closure
+ {
+ let sugg = format!(
+ "|({}){}|",
+ found_args
+ .iter()
+ .map(|arg| match arg {
+ ArgKind::Arg(name, _) => name.to_owned(),
+ _ => "_".to_owned(),
+ })
+ .collect::<Vec<String>>()
+ .join(", "),
+ // add type annotations if available
+ if found_args.iter().any(|arg| match arg {
+ ArgKind::Arg(_, ty) => ty != "_",
+ _ => false,
+ }) {
+ format!(
+ ": ({})",
+ fields
+ .iter()
+ .map(|(_, ty)| ty.to_owned())
+ .collect::<Vec<String>>()
+ .join(", ")
+ )
+ } else {
+ String::new()
+ },
+ );
+ err.span_suggestion_verbose(
+ found_span,
+ "change the closure to accept a tuple instead of individual arguments",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
+ err
+ }
- /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
- /// in that order, and returns the generic type corresponding to the
- /// argument of that trait (corresponding to the closure arguments).
fn type_implements_fn_trait(
&self,
param_env: ty::ParamEnv<'tcx>,
ty: ty::Binder<'tcx, Ty<'tcx>>,
constness: ty::BoundConstness,
polarity: ty::ImplPolarity,
- ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>;
-}
+ ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> {
+ self.commit_if_ok(|_| {
+ for trait_def_id in [
+ self.tcx.lang_items().fn_trait(),
+ self.tcx.lang_items().fn_mut_trait(),
+ self.tcx.lang_items().fn_once_trait(),
+ ] {
+ let Some(trait_def_id) = trait_def_id else { continue };
+ // Make a fresh inference variable so we can determine what the substitutions
+ // of the trait are.
+ let var = self.next_ty_var(TypeVariableOrigin {
+ span: DUMMY_SP,
+ kind: TypeVariableOriginKind::MiscVariable,
+ });
+ let substs = self.tcx.mk_substs_trait(ty.skip_binder(), &[var.into()]);
+ let obligation = Obligation::new(
+ ObligationCause::dummy(),
+ param_env,
+ ty.rebind(ty::TraitPredicate {
+ trait_ref: ty::TraitRef::new(trait_def_id, substs),
+ constness,
+ polarity,
+ })
+ .to_predicate(self.tcx),
+ );
+ let mut fulfill_cx = FulfillmentContext::new_in_snapshot();
+ fulfill_cx.register_predicate_obligation(self, obligation);
+ if fulfill_cx.select_all_or_error(self).is_empty() {
+ return Ok((
+ ty::ClosureKind::from_def_id(self.tcx, trait_def_id)
+ .expect("expected to map DefId to ClosureKind"),
+ ty.rebind(self.resolve_vars_if_possible(var)),
+ ));
+ }
+ }
-impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
+ Err(())
+ })
+ }
+}
+impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn report_fulfillment_errors(
&self,
errors: &[FulfillmentError<'tcx>],
@@ -251,6 +500,19 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
bug!();
}
+ fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) {
+ let suggested_limit = match self.tcx.recursion_limit() {
+ Limit(0) => Limit(2),
+ limit => limit * 2,
+ };
+ err.help(&format!(
+ "consider increasing the recursion limit by adding a \
+ `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
+ suggested_limit,
+ self.tcx.crate_name(LOCAL_CRATE),
+ ));
+ }
+
/// Reports that a cycle was detected which led to overflow and halts
/// compilation. This is equivalent to `report_overflow_error` except
/// that we can give a more helpful error message (and, in particular,
@@ -498,10 +760,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}
if let ObligationCauseCode::ObjectCastObligation(concrete_ty, obj_ty) = obligation.cause.code().peel_derives() &&
- Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
+ 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 {
@@ -511,6 +774,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
recursion_depth: obligation.recursion_depth,
};
if self.predicate_may_hold(&non_const_obligation) {
+ unsatisfied_const = true;
err.span_note(
span,
&format!(
@@ -606,11 +870,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// 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,
- )
+ 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
@@ -661,8 +925,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
);
}
}
- } else if !trait_ref.has_infer_types_or_consts()
- && self.predicate_can_apply(obligation.param_env, trait_ref)
+ } 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.
@@ -677,7 +941,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
None,
obligation.cause.body_id,
);
- } else if !suggested {
+ } 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(
@@ -840,12 +1104,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// Additional context information explaining why the closure only implements
// a particular trait.
- if let Some(typeck_results) = self.in_progress_typeck_results {
+ 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());
- let typeck_results = typeck_results.borrow();
match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
(ty::ClosureKind::FnOnce, Some((span, place))) => {
err.span_label(
@@ -994,6 +1257,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
found_span,
found_trait_ref,
expected_trait_ref,
+ obligation.cause.code(),
)
} else {
let (closure_span, found) = found_did
@@ -1042,7 +1306,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}
match obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::ConstEvaluatable(uv) => {
+ 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);
@@ -1088,250 +1355,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
err.emit();
}
-
- /// Given some node representing a fn-like thing in the HIR map,
- /// returns a span and `ArgKind` information that describes the
- /// arguments it expects. This can be supplied to
- /// `report_arg_count_mismatch`.
- fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)> {
- let sm = self.tcx.sess.source_map();
- let hir = self.tcx.hir();
- Some(match node {
- Node::Expr(&hir::Expr {
- kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }),
- ..
- }) => (
- fn_decl_span,
- hir.body(body)
- .params
- .iter()
- .map(|arg| {
- if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } =
- *arg.pat
- {
- Some(ArgKind::Tuple(
- Some(span),
- args.iter()
- .map(|pat| {
- sm.span_to_snippet(pat.span)
- .ok()
- .map(|snippet| (snippet, "_".to_owned()))
- })
- .collect::<Option<Vec<_>>>()?,
- ))
- } else {
- let name = sm.span_to_snippet(arg.pat.span).ok()?;
- Some(ArgKind::Arg(name, "_".to_owned()))
- }
- })
- .collect::<Option<Vec<ArgKind>>>()?,
- ),
- Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, ..), .. })
- | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. })
- | Node::TraitItem(&hir::TraitItem {
- kind: hir::TraitItemKind::Fn(ref sig, _), ..
- }) => (
- sig.span,
- sig.decl
- .inputs
- .iter()
- .map(|arg| match arg.kind {
- hir::TyKind::Tup(ref tys) => ArgKind::Tuple(
- Some(arg.span),
- vec![("_".to_owned(), "_".to_owned()); tys.len()],
- ),
- _ => ArgKind::empty(),
- })
- .collect::<Vec<ArgKind>>(),
- ),
- Node::Ctor(ref variant_data) => {
- let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id));
- (span, vec![ArgKind::empty(); variant_data.fields().len()])
- }
- _ => panic!("non-FnLike node found: {:?}", node),
- })
- }
-
- /// Reports an error when the number of arguments needed by a
- /// trait match doesn't match the number that the expression
- /// provides.
- fn report_arg_count_mismatch(
- &self,
- span: Span,
- found_span: Option<Span>,
- expected_args: Vec<ArgKind>,
- found_args: Vec<ArgKind>,
- is_closure: bool,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- let kind = if is_closure { "closure" } else { "function" };
-
- let args_str = |arguments: &[ArgKind], other: &[ArgKind]| {
- let arg_length = arguments.len();
- let distinct = matches!(other, &[ArgKind::Tuple(..)]);
- match (arg_length, arguments.get(0)) {
- (1, Some(&ArgKind::Tuple(_, ref fields))) => {
- format!("a single {}-tuple as argument", fields.len())
- }
- _ => format!(
- "{} {}argument{}",
- arg_length,
- if distinct && arg_length > 1 { "distinct " } else { "" },
- pluralize!(arg_length)
- ),
- }
- };
-
- let expected_str = args_str(&expected_args, &found_args);
- let found_str = args_str(&found_args, &expected_args);
-
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0593,
- "{} is expected to take {}, but it takes {}",
- kind,
- expected_str,
- found_str,
- );
-
- err.span_label(span, format!("expected {} that takes {}", kind, expected_str));
-
- if let Some(found_span) = found_span {
- err.span_label(found_span, format!("takes {}", found_str));
-
- // move |_| { ... }
- // ^^^^^^^^-- def_span
- //
- // move |_| { ... }
- // ^^^^^-- prefix
- let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span);
- // move |_| { ... }
- // ^^^-- pipe_span
- let pipe_span =
- if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span };
-
- // Suggest to take and ignore the arguments with expected_args_length `_`s if
- // found arguments is empty (assume the user just wants to ignore args in this case).
- // For example, if `expected_args_length` is 2, suggest `|_, _|`.
- if found_args.is_empty() && is_closure {
- let underscores = vec!["_"; expected_args.len()].join(", ");
- err.span_suggestion_verbose(
- pipe_span,
- &format!(
- "consider changing the closure to take and ignore the expected argument{}",
- pluralize!(expected_args.len())
- ),
- format!("|{}|", underscores),
- Applicability::MachineApplicable,
- );
- }
-
- if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] {
- if fields.len() == expected_args.len() {
- let sugg = fields
- .iter()
- .map(|(name, _)| name.to_owned())
- .collect::<Vec<String>>()
- .join(", ");
- err.span_suggestion_verbose(
- found_span,
- "change the closure to take multiple arguments instead of a single tuple",
- format!("|{}|", sugg),
- Applicability::MachineApplicable,
- );
- }
- }
- if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..]
- && fields.len() == found_args.len()
- && is_closure
- {
- let sugg = format!(
- "|({}){}|",
- found_args
- .iter()
- .map(|arg| match arg {
- ArgKind::Arg(name, _) => name.to_owned(),
- _ => "_".to_owned(),
- })
- .collect::<Vec<String>>()
- .join(", "),
- // add type annotations if available
- if found_args.iter().any(|arg| match arg {
- ArgKind::Arg(_, ty) => ty != "_",
- _ => false,
- }) {
- format!(
- ": ({})",
- fields
- .iter()
- .map(|(_, ty)| ty.to_owned())
- .collect::<Vec<String>>()
- .join(", ")
- )
- } else {
- String::new()
- },
- );
- err.span_suggestion_verbose(
- found_span,
- "change the closure to accept a tuple instead of individual arguments",
- sugg,
- Applicability::MachineApplicable,
- );
- }
- }
-
- err
- }
-
- fn type_implements_fn_trait(
- &self,
- param_env: ty::ParamEnv<'tcx>,
- ty: ty::Binder<'tcx, Ty<'tcx>>,
- constness: ty::BoundConstness,
- polarity: ty::ImplPolarity,
- ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> {
- self.commit_if_ok(|_| {
- for trait_def_id in [
- self.tcx.lang_items().fn_trait(),
- self.tcx.lang_items().fn_mut_trait(),
- self.tcx.lang_items().fn_once_trait(),
- ] {
- let Some(trait_def_id) = trait_def_id else { continue };
- // Make a fresh inference variable so we can determine what the substitutions
- // of the trait are.
- let var = self.next_ty_var(TypeVariableOrigin {
- span: DUMMY_SP,
- kind: TypeVariableOriginKind::MiscVariable,
- });
- let substs = self.tcx.mk_substs_trait(ty.skip_binder(), &[var.into()]);
- let obligation = Obligation::new(
- ObligationCause::dummy(),
- param_env,
- ty.rebind(ty::TraitPredicate {
- trait_ref: ty::TraitRef::new(trait_def_id, substs),
- constness,
- polarity,
- })
- .to_predicate(self.tcx),
- );
- let mut fulfill_cx = FulfillmentContext::new_in_snapshot();
- fulfill_cx.register_predicate_obligation(self, obligation);
- if fulfill_cx.select_all_or_error(self).is_empty() {
- return Ok((
- ty::ClosureKind::from_def_id(self.tcx, trait_def_id)
- .expect("expected to map DefId to ClosureKind"),
- ty.rebind(self.resolve_vars_if_possible(var)),
- ));
- }
- }
-
- Err(())
- })
- }
}
-trait InferCtxtPrivExt<'hir, 'tcx> {
+trait InferCtxtPrivExt<'tcx> {
// returns if `cond` not occurring implies that `error` does not occur - i.e., that
// `error` occurring implies that `cond` occurs.
fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool;
@@ -1412,7 +1438,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
fn predicate_can_apply(
&self,
param_env: ty::ParamEnv<'tcx>,
- pred: ty::PolyTraitRef<'tcx>,
+ pred: ty::PolyTraitPredicate<'tcx>,
) -> bool;
fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>);
@@ -1430,13 +1456,13 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
predicate: ty::Predicate<'tcx>,
);
- fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'hir>);
+ fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>);
fn maybe_indirection_for_unsized(
&self,
err: &mut Diagnostic,
- item: &'hir Item<'hir>,
- param: &'hir GenericParam<'hir>,
+ item: &'tcx Item<'tcx>,
+ param: &'tcx GenericParam<'tcx>,
) -> bool;
fn is_recursive_obligation(
@@ -1446,7 +1472,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
) -> bool;
}
-impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// returns if `cond` not occurring implies that `error` does not occur - i.e., that
// `error` occurring implies that `cond` occurs.
fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool {
@@ -1540,6 +1566,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
}
diag.emit();
}
+ FulfillmentErrorCode::CodeCycle(ref cycle) => {
+ self.report_overflow_error_cycle(cycle);
+ }
}
}
@@ -1636,7 +1665,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
..
})
| hir::Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::TyAlias(ty),
+ kind: hir::ImplItemKind::Type(ty),
..
}),
) => Some((ty.span, format!("type mismatch resolving `{}`", predicate))),
@@ -1895,7 +1924,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
// FIXME(compiler-errors): This could be generalized, both to
// be more granular, and probably look past other `#[fundamental]`
// types, too.
- self.tcx.visibility(def.did()).is_accessible_from(body_id.owner, self.tcx)
+ self.tcx
+ .visibility(def.did())
+ .is_accessible_from(body_id.owner.def_id, self.tcx)
} else {
true
}
@@ -1905,16 +1936,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
}
let normalize = |candidate| {
- self.tcx.infer_ctxt().enter(|ref infcx| {
- let normalized = infcx
- .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
- .normalize(candidate)
- .ok();
- match normalized {
- Some(normalized) => normalized.value,
- None => candidate,
- }
- })
+ let infcx = self.tcx.infer_ctxt().build();
+ infcx
+ .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
+ .normalize(candidate)
+ .map_or(candidate, |normalized| normalized.value)
};
// Sort impl candidates so that ordering is consistent for UI tests.
@@ -2088,7 +2114,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
// Pick the first substitution that still contains inference variables as the one
// we're going to emit an error for. If there are none (see above), fall back to
// a more general error.
- let subst = data.trait_ref.substs.iter().find(|s| s.has_infer_types_or_consts());
+ let subst = data.trait_ref.substs.iter().find(|s| s.has_non_region_infer());
let mut err = if let Some(subst) = subst {
self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283, true)
@@ -2258,13 +2284,22 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
trait_impls.non_blanket_impls().len()
)
};
-
+ let mut suggestions = vec![(
+ trait_path_segment.ident.span.shrink_to_lo(),
+ format!("<{} as ", self.tcx.type_of(impl_def_id))
+ )];
+ if let Some(generic_arg) = trait_path_segment.args {
+ let between_span = trait_path_segment.ident.span.between(generic_arg.span_ext);
+ // get rid of :: between Trait and <type>
+ // must be '::' between them, otherwise the parser won't accept the code
+ suggestions.push((between_span, "".to_string(),));
+ suggestions.push((generic_arg.span_ext.shrink_to_hi(), format!(">")));
+ } else {
+ suggestions.push((trait_path_segment.ident.span.shrink_to_hi(), format!(">")));
+ }
err.multipart_suggestion(
message,
- vec![
- (trait_path_segment.ident.span.shrink_to_lo(), format!("<{} as ", self.tcx.def_path(impl_def_id).to_string_no_crate_verbose())),
- (trait_path_segment.ident.span.shrink_to_hi(), format!(">"))
- ],
+ suggestions,
Applicability::MaybeIncorrect
);
}
@@ -2309,7 +2344,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
.substs
.iter()
.chain(Some(data.term.into_arg()))
- .find(|g| g.has_infer_types_or_consts());
+ .find(|g| g.has_non_region_infer());
if let Some(subst) = subst {
let mut err = self.emit_inference_failure_err(
body_id,
@@ -2338,7 +2373,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
if predicate.references_error() || self.is_tainted_by_errors() {
return;
}
- let subst = data.substs.iter().find(|g| g.has_infer_types_or_consts());
+ let subst = data.walk().find(|g| g.is_non_region_infer());
if let Some(subst) = subst {
let err = self.emit_inference_failure_err(
body_id,
@@ -2478,10 +2513,10 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
fn predicate_can_apply(
&self,
param_env: ty::ParamEnv<'tcx>,
- pred: ty::PolyTraitRef<'tcx>,
+ pred: ty::PolyTraitPredicate<'tcx>,
) -> bool {
struct ParamToVarFolder<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
}
@@ -2522,7 +2557,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
let obligation = Obligation::new(
ObligationCause::dummy(),
param_env,
- cleaned_pred.without_const().to_predicate(selcx.tcx()),
+ cleaned_pred.to_predicate(selcx.tcx()),
);
self.predicate_may_hold(&obligation)
@@ -2567,12 +2602,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
}
#[instrument(level = "debug", skip_all)]
- fn maybe_suggest_unsized_generics<'hir>(
- &self,
- err: &mut Diagnostic,
- span: Span,
- node: Node<'hir>,
- ) {
+ fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>) {
let Some(generics) = node.generics() else {
return;
};
@@ -2623,11 +2653,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
);
}
- fn maybe_indirection_for_unsized<'hir>(
+ fn maybe_indirection_for_unsized(
&self,
err: &mut Diagnostic,
- item: &'hir Item<'hir>,
- param: &'hir GenericParam<'hir>,
+ item: &Item<'tcx>,
+ param: &GenericParam<'tcx>,
) -> bool {
// Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
// borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
@@ -2727,82 +2757,6 @@ impl<'v> Visitor<'v> for FindTypeParam {
}
}
-pub fn recursive_type_with_infinite_size_error<'tcx>(
- tcx: TyCtxt<'tcx>,
- type_def_id: DefId,
- spans: Vec<(Span, Option<hir::HirId>)>,
-) {
- assert!(type_def_id.is_local());
- let span = tcx.def_span(type_def_id);
- let path = tcx.def_path_str(type_def_id);
- let mut err =
- struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", path);
- err.span_label(span, "recursive type has infinite size");
- for &(span, _) in &spans {
- err.span_label(span, "recursive without indirection");
- }
- let msg = format!(
- "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `{}` representable",
- path,
- );
- if spans.len() <= 4 {
- // FIXME(compiler-errors): This suggestion might be erroneous if Box is shadowed
- err.multipart_suggestion(
- &msg,
- spans
- .into_iter()
- .flat_map(|(span, field_id)| {
- if let Some(generic_span) = get_option_generic_from_field_id(tcx, field_id) {
- // If we match an `Option` and can grab the span of the Option's generic, then
- // suggest boxing the generic arg for a non-null niche optimization.
- vec![
- (generic_span.shrink_to_lo(), "Box<".to_string()),
- (generic_span.shrink_to_hi(), ">".to_string()),
- ]
- } else {
- vec![
- (span.shrink_to_lo(), "Box<".to_string()),
- (span.shrink_to_hi(), ">".to_string()),
- ]
- }
- })
- .collect(),
- Applicability::HasPlaceholders,
- );
- } else {
- err.help(&msg);
- }
- err.emit();
-}
-
-/// Extract the span for the generic type `T` of `Option<T>` in a field definition
-fn get_option_generic_from_field_id(tcx: TyCtxt<'_>, field_id: Option<hir::HirId>) -> Option<Span> {
- let node = tcx.hir().find(field_id?);
-
- // Expect a field from our field_id
- let Some(hir::Node::Field(field_def)) = node
- else { bug!("Expected HirId corresponding to FieldDef, found: {:?}", node) };
-
- // Match a type that is a simple QPath with no Self
- let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = &field_def.ty.kind
- else { return None };
-
- // Check if the path we're checking resolves to Option
- let hir::def::Res::Def(_, did) = path.res
- else { return None };
-
- // Bail if this path doesn't describe `::core::option::Option`
- if !tcx.is_diagnostic_item(sym::Option, did) {
- return None;
- }
-
- // Match a single generic arg in the 0th path segment
- let generic_arg = path.segments.last()?.args?.args.get(0)?;
-
- // Take the span out of the type, if it's a type
- if let hir::GenericArg::Type(generic_ty) = generic_arg { Some(generic_ty.span) } else { None }
-}
-
/// Summarizes information
#[derive(Clone)]
pub enum ArgKind {
@@ -2847,3 +2801,8 @@ impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor {
}
}
}
+
+pub enum DefIdOrName {
+ DefId(DefId),
+ Name(&'static str),
+}
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 e11a42201..5eef54c63 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
@@ -1,17 +1,17 @@
use super::{
ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation,
};
-use crate::infer::InferCtxt;
+use crate::infer::error_reporting::TypeErrCtxt;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::{Subst, SubstsRef};
+use rustc_middle::ty::SubstsRef;
use rustc_middle::ty::{self, GenericParamDefKind};
use rustc_span::symbol::sym;
use std::iter;
use super::InferCtxtPrivExt;
-pub trait InferCtxtExt<'tcx> {
+pub trait TypeErrCtxtExt<'tcx> {
/*private*/
fn impl_similar_to(
&self,
@@ -29,7 +29,7 @@ pub trait InferCtxtExt<'tcx> {
) -> OnUnimplementedNote;
}
-impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
+impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn impl_similar_to(
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
@@ -164,6 +164,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
}
+ if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
+ flags.push((sym::cause, Some("MainFunctionType".to_string())));
+ }
+
// Add all types without trimmed paths.
ty::print::with_no_trimmed_paths!({
let generics = self.tcx.generics_of(def_id);
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 13d9c1600..8c41d9d24 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1,5 +1,5 @@
use super::{
- EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
+ DefIdOrName, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
SelectionContext,
};
@@ -7,6 +7,7 @@ use crate::autoderef::Autoderef;
use crate::infer::InferCtxt;
use crate::traits::normalize_to;
+use hir::def::CtorOf;
use hir::HirId;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -20,7 +21,9 @@ use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
+use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::hir::map;
use rustc_middle::ty::{
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
@@ -28,9 +31,7 @@ use rustc_middle::ty::{
ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
};
use rustc_middle::ty::{TypeAndMut, TypeckResults};
-use rustc_session::Limit;
-use rustc_span::def_id::LOCAL_CRATE;
-use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span, DUMMY_SP};
use rustc_target::spec::abi;
use std::fmt;
@@ -62,7 +63,7 @@ impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
// meet an obligation
fn try_get_upvar_span<F>(
&self,
- infer_context: &InferCtxt<'a, 'tcx>,
+ infer_context: &InferCtxt<'tcx>,
generator_did: DefId,
ty_matches: F,
) -> Option<GeneratorInteriorOrUpvar>
@@ -168,7 +169,7 @@ impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
}
// This trait is public to expose the diagnostics methods to clippy.
-pub trait InferCtxtExt<'tcx> {
+pub trait TypeErrCtxtExt<'tcx> {
fn suggest_restricting_param_bound(
&self,
err: &mut Diagnostic,
@@ -255,8 +256,15 @@ pub trait InferCtxtExt<'tcx> {
found_span: Option<Span>,
found: ty::PolyTraitRef<'tcx>,
expected: ty::PolyTraitRef<'tcx>,
+ cause: &ObligationCauseCode<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+ fn note_conflicting_closure_bounds(
+ &self,
+ cause: &ObligationCauseCode<'tcx>,
+ err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ );
+
fn suggest_fully_qualified_path(
&self,
err: &mut Diagnostic,
@@ -296,8 +304,6 @@ pub trait InferCtxtExt<'tcx> {
) where
T: fmt::Display;
- fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
-
/// Suggest to await before try: future? => future.await?
fn suggest_await_before_try(
&self,
@@ -461,7 +467,7 @@ fn suggest_restriction<'tcx>(
}
}
-impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
+impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn suggest_restricting_param_bound(
&self,
mut err: &mut Diagnostic,
@@ -659,7 +665,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
_ => {}
}
- hir_id = self.tcx.hir().local_def_id_to_hir_id(self.tcx.hir().get_parent_item(hir_id));
+ hir_id = self.tcx.hir().get_parent_item(hir_id).into();
}
}
@@ -675,9 +681,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// It only make sense when suggesting dereferences for arguments
let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code()
else { return false; };
- let Some(typeck_results) = self.in_progress_typeck_results
+ let Some(typeck_results) = &self.typeck_results
else { return false; };
- let typeck_results = typeck_results.borrow();
let hir::Node::Expr(expr) = self.tcx.hir().get(*arg_hir_id)
else { return false; };
let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr)
@@ -809,74 +814,136 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
err: &mut Diagnostic,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool {
- // Skipping binder here, remapping below
- let self_ty = trait_pred.self_ty().skip_binder();
-
- let (def_id, output_ty, callable) = match *self_ty.kind() {
- ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"),
- ty::FnDef(def_id, _) => (def_id, self_ty.fn_sig(self.tcx).output(), "function"),
- _ => return false,
- };
- let msg = format!("use parentheses to call the {}", callable);
+ if let ty::PredicateKind::Trait(trait_pred) = obligation.predicate.kind().skip_binder()
+ && Some(trait_pred.def_id()) == self.tcx.lang_items().sized_trait()
+ {
+ // Don't suggest calling to turn an unsized type into a sized type
+ return false;
+ }
- // "We should really create a single list of bound vars from the combined vars
- // from the predicate and function, but instead we just liberate the function bound vars"
- let output_ty = self.tcx.liberate_late_bound_regions(def_id, output_ty);
+ // This is duplicated from `extract_callable_info` in typeck, which
+ // relies on autoderef, so we can't use it here.
+ let found = trait_pred.self_ty().skip_binder().peel_refs();
+ let Some((def_id_or_name, output, inputs)) = (match *found.kind()
+ {
+ ty::FnPtr(fn_sig) => {
+ Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs()))
+ }
+ ty::FnDef(def_id, _) => {
+ let fn_sig = found.fn_sig(self.tcx);
+ Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
+ }
+ ty::Closure(def_id, substs) => {
+ let fn_sig = substs.as_closure().sig();
+ Some((
+ DefIdOrName::DefId(def_id),
+ fn_sig.output(),
+ fn_sig.inputs().map_bound(|inputs| &inputs[1..]),
+ ))
+ }
+ ty::Opaque(def_id, substs) => {
+ self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
+ if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
+ && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
+ // args tuple will always be substs[1]
+ && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+ {
+ Some((
+ DefIdOrName::DefId(def_id),
+ pred.kind().rebind(proj.term.ty().unwrap()),
+ pred.kind().rebind(args.as_slice()),
+ ))
+ } else {
+ None
+ }
+ })
+ }
+ ty::Dynamic(data, _, ty::Dyn) => {
+ data.iter().find_map(|pred| {
+ if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
+ && Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output()
+ // for existential projection, substs are shifted over by 1
+ && let ty::Tuple(args) = proj.substs.type_at(0).kind()
+ {
+ Some((
+ DefIdOrName::Name("trait object"),
+ pred.rebind(proj.term.ty().unwrap()),
+ pred.rebind(args.as_slice()),
+ ))
+ } else {
+ None
+ }
+ })
+ }
+ ty::Param(_) => {
+ obligation.param_env.caller_bounds().iter().find_map(|pred| {
+ if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
+ && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
+ && proj.projection_ty.self_ty() == found
+ // args tuple will always be substs[1]
+ && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+ {
+ Some((
+ DefIdOrName::Name("type parameter"),
+ pred.kind().rebind(proj.term.ty().unwrap()),
+ pred.kind().rebind(args.as_slice()),
+ ))
+ } else {
+ None
+ }
+ })
+ }
+ _ => None,
+ }) else { return false; };
+ let output = self.replace_bound_vars_with_fresh_vars(
+ obligation.cause.span,
+ LateBoundRegionConversionTime::FnCall,
+ output,
+ );
+ let inputs = inputs.skip_binder().iter().map(|ty| {
+ self.replace_bound_vars_with_fresh_vars(
+ obligation.cause.span,
+ LateBoundRegionConversionTime::FnCall,
+ inputs.rebind(*ty),
+ )
+ });
// Remapping bound vars here
- let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output_ty));
+ let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output));
let new_obligation =
self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
-
- match self.evaluate_obligation(&new_obligation) {
- Ok(
- EvaluationResult::EvaluatedToOk
- | EvaluationResult::EvaluatedToOkModuloRegions
- | EvaluationResult::EvaluatedToOkModuloOpaqueTypes
- | EvaluationResult::EvaluatedToAmbig,
- ) => {}
- _ => return false,
+ if !self.predicate_must_hold_modulo_regions(&new_obligation) {
+ return false;
}
- let hir = self.tcx.hir();
+
// Get the name of the callable and the arguments to be used in the suggestion.
- let (snippet, sugg) = match hir.get_if_local(def_id) {
- Some(hir::Node::Expr(hir::Expr {
- kind: hir::ExprKind::Closure(hir::Closure { fn_decl, fn_decl_span, .. }),
- ..
- })) => {
- err.span_label(*fn_decl_span, "consider calling this closure");
- let Some(name) = self.get_closure_name(def_id, err, &msg) else {
- return false;
- };
- let args = fn_decl.inputs.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
- let sugg = format!("({})", args);
- (format!("{}{}", name, sugg), sugg)
- }
- Some(hir::Node::Item(hir::Item {
- ident,
- kind: hir::ItemKind::Fn(.., body_id),
- ..
- })) => {
- err.span_label(ident.span, "consider calling this function");
- let body = hir.body(*body_id);
- let args = body
- .params
- .iter()
- .map(|arg| match &arg.pat.kind {
- hir::PatKind::Binding(_, _, ident, None)
- // FIXME: provide a better suggestion when encountering `SelfLower`, it
- // should suggest a method call.
- if ident.name != kw::SelfLower => ident.to_string(),
- _ => "_".to_string(),
- })
- .collect::<Vec<_>>()
- .join(", ");
- let sugg = format!("({})", args);
- (format!("{}{}", ident, sugg), sugg)
- }
- _ => return false,
+ let hir = self.tcx.hir();
+
+ let msg = match def_id_or_name {
+ DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
+ DefKind::Ctor(CtorOf::Struct, _) => {
+ "use parentheses to construct this tuple struct".to_string()
+ }
+ DefKind::Ctor(CtorOf::Variant, _) => {
+ "use parentheses to construct this tuple variant".to_string()
+ }
+ kind => format!("use parentheses to call this {}", kind.descr(def_id)),
+ },
+ DefIdOrName::Name(name) => format!("use parentheses to call this {name}"),
};
+
+ let args = inputs
+ .map(|ty| {
+ if ty.is_suggestable(self.tcx, false) {
+ format!("/* {ty} */")
+ } else {
+ "/* value */".to_string()
+ }
+ })
+ .collect::<Vec<_>>()
+ .join(", ");
+
if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArgumentObligation { .. })
&& obligation.cause.span.can_be_used_for_suggestions()
{
@@ -887,11 +954,36 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
err.span_suggestion_verbose(
obligation.cause.span.shrink_to_hi(),
&msg,
- sugg,
+ format!("({args})"),
Applicability::HasPlaceholders,
);
- } else {
- err.help(&format!("{}: `{}`", msg, snippet));
+ } else if let DefIdOrName::DefId(def_id) = def_id_or_name {
+ let name = match hir.get_if_local(def_id) {
+ Some(hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Closure(hir::Closure { fn_decl_span, .. }),
+ ..
+ })) => {
+ err.span_label(*fn_decl_span, "consider calling this closure");
+ let Some(name) = self.get_closure_name(def_id, err, &msg) else {
+ return false;
+ };
+ name.to_string()
+ }
+ Some(hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(..), .. })) => {
+ err.span_label(ident.span, "consider calling this function");
+ ident.to_string()
+ }
+ Some(hir::Node::Ctor(..)) => {
+ let name = self.tcx.def_path_str(def_id);
+ err.span_label(
+ self.tcx.def_span(def_id),
+ format!("consider calling the constructor for `{}`", name),
+ );
+ name
+ }
+ _ => return false,
+ };
+ err.help(&format!("{msg}: `{name}({args})`"));
}
true
}
@@ -1176,8 +1268,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
&format!("this call returns `{}`", pred.self_ty()),
);
}
- if let Some(typeck_results) =
- self.in_progress_typeck_results.map(|t| t.borrow())
+ 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, .. })) =
@@ -1231,7 +1322,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
return;
}
let trait_pred = self.resolve_vars_if_possible(trait_pred);
- if trait_pred.has_infer_types_or_consts() {
+ if trait_pred.has_non_region_infer() {
// Do not ICE while trying to find if a reborrow would succeed on a trait with
// unresolved bindings.
return;
@@ -1300,8 +1391,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
&& let Some(stmt) = blk.stmts.last()
&& let hir::StmtKind::Semi(expr) = stmt.kind
// Only suggest this if the expression behind the semicolon implements the predicate
- && let Some(typeck_results) = self.in_progress_typeck_results
- && let Some(ty) = typeck_results.borrow().expr_ty_opt(expr)
+ && let Some(typeck_results) = &self.typeck_results
+ && let Some(ty) = typeck_results.expr_ty_opt(expr)
&& self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(
obligation.param_env, trait_pred.map_bound(|trait_pred| (trait_pred, ty))
))
@@ -1390,7 +1481,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let mut visitor = ReturnsVisitor::default();
visitor.visit_body(&body);
- let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap();
+ 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
@@ -1425,7 +1516,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let mut spans_and_needs_box = vec![];
match liberated_sig.output().kind() {
- ty::Dynamic(predicates, _, _) => {
+ ty::Dynamic(predicates, _, ty::Dyn) => {
let cause = ObligationCause::misc(ret_ty.span, fn_hir_id);
let param_env = ty::ParamEnv::empty();
@@ -1573,7 +1664,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// Point at all the `return`s in the function as they have failed trait bounds.
let mut visitor = ReturnsVisitor::default();
visitor.visit_body(&body);
- let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap();
+ let typeck_results = self.typeck_results.as_ref().unwrap();
for expr in &visitor.returns {
if let Some(returned_ty) = typeck_results.node_type_opt(expr.hir_id) {
let ty = self.resolve_vars_if_possible(returned_ty);
@@ -1589,9 +1680,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
found_span: Option<Span>,
found: ty::PolyTraitRef<'tcx>,
expected: ty::PolyTraitRef<'tcx>,
+ cause: &ObligationCauseCode<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
pub(crate) fn build_fn_sig_ty<'tcx>(
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
) -> Ty<'tcx> {
let inputs = trait_ref.skip_binder().substs.type_at(1);
@@ -1650,9 +1742,68 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let signature_kind = format!("{argument_kind} signature");
err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str);
+ self.note_conflicting_closure_bounds(cause, &mut err);
+
err
}
+ // Add a note if there are two `Fn`-family bounds that have conflicting argument
+ // requirements, which will always cause a closure to have a type error.
+ fn note_conflicting_closure_bounds(
+ &self,
+ cause: &ObligationCauseCode<'tcx>,
+ err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ ) {
+ // First, look for an `ExprBindingObligation`, which means we can get
+ // the unsubstituted predicate list of the called function. And check
+ // that the predicate that we failed to satisfy is a `Fn`-like trait.
+ if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = cause
+ && let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
+ && let Some(pred) = predicates.predicates.get(*idx)
+ && let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder()
+ && ty::ClosureKind::from_def_id(self.tcx, trait_pred.def_id()).is_some()
+ {
+ let expected_self =
+ self.tcx.anonymize_late_bound_regions(pred.kind().rebind(trait_pred.self_ty()));
+ let expected_substs = self
+ .tcx
+ .anonymize_late_bound_regions(pred.kind().rebind(trait_pred.trait_ref.substs));
+
+ // Find another predicate whose self-type is equal to the expected self type,
+ // but whose substs don't match.
+ let other_pred = std::iter::zip(&predicates.predicates, &predicates.spans)
+ .enumerate()
+ .find(|(other_idx, (pred, _))| match pred.kind().skip_binder() {
+ ty::PredicateKind::Trait(trait_pred)
+ if ty::ClosureKind::from_def_id(self.tcx, trait_pred.def_id())
+ .is_some()
+ && other_idx != idx
+ // Make sure that the self type matches
+ // (i.e. constraining this closure)
+ && expected_self
+ == self.tcx.anonymize_late_bound_regions(
+ pred.kind().rebind(trait_pred.self_ty()),
+ )
+ // But the substs don't match (i.e. incompatible args)
+ && expected_substs
+ != self.tcx.anonymize_late_bound_regions(
+ pred.kind().rebind(trait_pred.trait_ref.substs),
+ ) =>
+ {
+ true
+ }
+ _ => false,
+ });
+ // If we found one, then it's very likely the cause of the error.
+ if let Some((_, (_, other_pred_span))) = other_pred {
+ err.span_note(
+ *other_pred_span,
+ "closure inferred to have a different signature due to this bound",
+ );
+ }
+ }
+ }
+
fn suggest_fully_qualified_path(
&self,
err: &mut Diagnostic,
@@ -1841,12 +1992,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let span = self.tcx.def_span(generator_did);
- let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow());
let generator_did_root = self.tcx.typeck_root_def_id(generator_did);
debug!(
?generator_did,
?generator_did_root,
- in_progress_typeck_results.hir_owner = ?in_progress_typeck_results.as_ref().map(|t| t.hir_owner),
+ typeck_results.hir_owner = ?self.typeck_results.as_ref().map(|t| t.hir_owner),
?span,
);
@@ -1901,7 +2051,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// type-checking; otherwise, get them by performing a query. This is needed to avoid
// cycles. If we can't use resolved types because the generator comes from another crate,
// we still provide a targeted error but without all the relevant spans.
- let generator_data: Option<GeneratorData<'tcx, '_>> = match &in_progress_typeck_results {
+ let generator_data: Option<GeneratorData<'tcx, '_>> = match &self.typeck_results {
Some(t) if t.hir_owner.to_def_id() == generator_did_root => {
Some(GeneratorData::Local(&t))
}
@@ -2707,19 +2857,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
if let Some(Node::Expr(expr @ hir::Expr { kind: hir::ExprKind::Block(..), .. })) =
hir.find(arg_hir_id)
{
- let in_progress_typeck_results =
- self.in_progress_typeck_results.map(|t| t.borrow());
let parent_id = hir.get_parent_item(arg_hir_id);
- let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results {
+ let typeck_results: &TypeckResults<'tcx> = match &self.typeck_results {
Some(t) if t.hir_owner == parent_id => t,
- _ => self.tcx.typeck(parent_id),
+ _ => self.tcx.typeck(parent_id.def_id),
};
- let ty = typeck_results.expr_ty_adjusted(expr);
- let span = expr.peel_blocks().span;
+ let expr = expr.peel_blocks();
+ let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error());
+ let span = expr.span;
if Some(span) != err.span.primary_span() {
err.span_label(
span,
- &if ty.references_error() {
+ if ty.references_error() {
String::new()
} else {
format!("this tail expression is of type `{:?}`", ty)
@@ -2796,19 +2945,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}
}
- fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) {
- let suggested_limit = match self.tcx.recursion_limit() {
- Limit(0) => Limit(2),
- limit => limit * 2,
- };
- err.help(&format!(
- "consider increasing the recursion limit by adding a \
- `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
- suggested_limit,
- self.tcx.crate_name(LOCAL_CRATE),
- ));
- }
-
#[instrument(
level = "debug", skip(self, err), fields(trait_pred.self_ty = ?trait_pred.self_ty())
)]
@@ -2890,19 +3026,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
ObligationCauseCode::BinOp { rhs_span: Some(span), is_lit, .. } if *is_lit => span,
_ => return,
};
- match (
- trait_ref.skip_binder().self_ty().kind(),
- trait_ref.skip_binder().substs.type_at(1).kind(),
- ) {
- (ty::Float(_), ty::Infer(InferTy::IntVar(_))) => {
- err.span_suggestion_verbose(
- rhs_span.shrink_to_hi(),
- "consider using a floating-point literal by writing it with `.0`",
- ".0",
- Applicability::MaybeIncorrect,
- );
- }
- _ => {}
+ if let ty::Float(_) = trait_ref.skip_binder().self_ty().kind()
+ && let ty::Infer(InferTy::IntVar(_)) = trait_ref.skip_binder().substs.type_at(1).kind()
+ {
+ err.span_suggestion_verbose(
+ rhs_span.shrink_to_hi(),
+ "consider using a floating-point literal by writing it with `.0`",
+ ".0",
+ Applicability::MaybeIncorrect,
+ );
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index a81fef60a..a417e1440 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -25,10 +25,9 @@ use super::Unimplemented;
use super::{FulfillmentError, FulfillmentErrorCode};
use super::{ObligationCause, PredicateObligation};
-use crate::traits::error_reporting::InferCtxtExt as _;
use crate::traits::project::PolyProjectionObligation;
use crate::traits::project::ProjectionCacheKeyExt as _;
-use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
/// Note that we include both the `ParamEnv` and the `Predicate`,
@@ -103,7 +102,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
}
/// Attempts to select obligations using `selcx`.
- fn select(&mut self, selcx: &mut SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ fn select(&mut self, selcx: SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
let _enter = span.enter();
@@ -138,7 +137,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
#[instrument(level = "debug", skip(self, infcx, param_env, cause))]
fn normalize_projection_type(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
cause: ObligationCause<'tcx>,
@@ -166,7 +165,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn register_predicate_obligation(
&mut self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
obligation: PredicateObligation<'tcx>,
) {
// this helps to reduce duplicate errors, as well as making
@@ -183,7 +182,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
}
- fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
{
let errors = self.select_where_possible(infcx);
if !errors.is_empty() {
@@ -194,12 +193,9 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
}
- fn select_where_possible(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Vec<FulfillmentError<'tcx>> {
- let mut selcx = SelectionContext::new(infcx);
- self.select(&mut selcx)
+ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ let selcx = SelectionContext::new(infcx);
+ self.select(selcx)
}
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
@@ -211,8 +207,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
}
}
-struct FulfillProcessor<'a, 'b, 'tcx> {
- selcx: &'a mut SelectionContext<'b, 'tcx>,
+struct FulfillProcessor<'a, 'tcx> {
+ selcx: SelectionContext<'a, 'tcx>,
}
fn mk_pending(os: Vec<PredicateObligation<'_>>) -> Vec<PendingPredicateObligation<'_>> {
@@ -221,9 +217,10 @@ fn mk_pending(os: Vec<PredicateObligation<'_>>) -> Vec<PendingPredicateObligatio
.collect()
}
-impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
+impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
type Obligation = PendingPredicateObligation<'tcx>;
type Error = FulfillmentErrorCode<'tcx>;
+ type OUT = Outcome<Self::Obligation, Self::Error>;
/// Identifies whether a predicate obligation needs processing.
///
@@ -279,7 +276,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
debug!(?obligation, "pre-resolve");
- if obligation.predicate.has_infer_types_or_consts() {
+ if obligation.predicate.has_non_region_infer() {
obligation.predicate =
self.selcx.infcx().resolve_vars_if_possible(obligation.predicate);
}
@@ -291,7 +288,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
if obligation.predicate.has_projections() {
let mut obligations = Vec::new();
let predicate = crate::traits::project::try_normalize_with_depth_to(
- self.selcx,
+ &mut self.selcx,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
@@ -358,7 +355,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
}
ty::PredicateKind::RegionOutlives(data) => {
- if infcx.considering_regions || data.has_placeholders() {
+ if infcx.considering_regions {
infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data));
}
@@ -479,9 +476,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
Err(NotConstEvaluatable::MentionsInfer) => {
pending_obligation.stalled_on.clear();
pending_obligation.stalled_on.extend(
- uv.substs
- .iter()
- .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
+ uv.walk().filter_map(TyOrConstInferVar::maybe_from_generic_arg),
);
ProcessResult::Unchanged
}
@@ -495,19 +490,20 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
}
ty::PredicateKind::ConstEquate(c1, c2) => {
+ assert!(
+ self.selcx.tcx().features().generic_const_exprs,
+ "`ConstEquate` without a feature gate: {c1:?} {c2:?}",
+ );
debug!(?c1, ?c2, "equating consts");
- let tcx = self.selcx.tcx();
- if tcx.features().generic_const_exprs {
- // FIXME: we probably should only try to unify abstract constants
- // if the constants depend on generic parameters.
- //
- // Let's just see where this breaks :shrug:
- if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
- (c1.kind(), c2.kind())
- {
- if infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
- return ProcessResult::Changed(vec![]);
- }
+ // FIXME: we probably should only try to unify abstract constants
+ // if the constants depend on generic parameters.
+ //
+ // Let's just see where this breaks :shrug:
+ if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
+ (c1.kind(), c2.kind())
+ {
+ if infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
+ return ProcessResult::Changed(vec![]);
}
}
@@ -569,7 +565,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
)
}
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
- if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() {
+ if c1.has_non_region_infer() || c2.has_non_region_infer() {
ProcessResult::Unchanged
} else {
// Two different constants using generic parameters ~> error.
@@ -594,19 +590,21 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
&mut self,
cycle: I,
_marker: PhantomData<&'c PendingPredicateObligation<'tcx>>,
- ) where
+ ) -> Result<(), FulfillmentErrorCode<'tcx>>
+ where
I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>,
{
if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) {
debug!("process_child_obligations: coinductive match");
+ Ok(())
} else {
let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect();
- self.selcx.infcx().report_overflow_error_cycle(&cycle);
+ Err(FulfillmentErrorCode::CodeCycle(cycle))
}
}
}
-impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
+impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
#[instrument(level = "debug", skip(self, obligation, stalled_on))]
fn process_trait_obligation(
&mut self,
@@ -641,7 +639,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
// information about the types in the trait.
stalled_on.clear();
stalled_on.extend(substs_infer_vars(
- self.selcx,
+ &self.selcx,
trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs),
));
@@ -693,12 +691,12 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
}
}
- match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
+ match project::poly_project_and_unify_type(&mut self.selcx, &project_obligation) {
ProjectAndUnifyResult::Holds(os) => ProcessResult::Changed(mk_pending(os)),
ProjectAndUnifyResult::FailedNormalization => {
stalled_on.clear();
stalled_on.extend(substs_infer_vars(
- self.selcx,
+ &self.selcx,
project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs),
));
ProcessResult::Unchanged
@@ -716,7 +714,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
/// Returns the set of inference variables contained in `substs`.
fn substs_infer_vars<'a, 'tcx>(
- selcx: &mut SelectionContext<'a, 'tcx>,
+ selcx: &SelectionContext<'a, 'tcx>,
substs: ty::Binder<'tcx, SubstsRef<'tcx>>,
) -> impl Iterator<Item = TyOrConstInferVar<'tcx>> {
selcx
@@ -724,11 +722,11 @@ fn substs_infer_vars<'a, 'tcx>(
.resolve_vars_if_possible(substs)
.skip_binder() // ok because this check doesn't care about regions
.iter()
- .filter(|arg| arg.has_infer_types_or_consts())
+ .filter(|arg| arg.has_non_region_infer())
.flat_map(|arg| {
let mut walker = arg.walk();
while let Some(c) = walker.next() {
- if !c.has_infer_types_or_consts() {
+ if !c.has_non_region_infer() {
walker.visited.remove(&c);
walker.skip_current_subtree();
}
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index e1bd48ba8..be603c609 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -7,7 +7,7 @@ use rustc_hir as hir;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
-use crate::traits::error_reporting::InferCtxtExt;
+use crate::traits::error_reporting::TypeErrCtxtExt;
#[derive(Clone)]
pub enum CopyImplementationError<'tcx> {
@@ -23,65 +23,64 @@ pub fn can_type_implement_copy<'tcx>(
parent_cause: ObligationCause<'tcx>,
) -> Result<(), CopyImplementationError<'tcx>> {
// FIXME: (@jroesch) float this code up
- tcx.infer_ctxt().enter(|infcx| {
- let (adt, substs) = match self_type.kind() {
- // These types used to have a builtin impl.
- // Now libcore provides that impl.
- ty::Uint(_)
- | ty::Int(_)
- | ty::Bool
- | ty::Float(_)
- | ty::Char
- | ty::RawPtr(..)
- | ty::Never
- | ty::Ref(_, _, hir::Mutability::Not)
- | ty::Array(..) => return Ok(()),
+ let infcx = tcx.infer_ctxt().build();
+ let (adt, substs) = match self_type.kind() {
+ // These types used to have a builtin impl.
+ // Now libcore provides that impl.
+ ty::Uint(_)
+ | ty::Int(_)
+ | ty::Bool
+ | ty::Float(_)
+ | ty::Char
+ | ty::RawPtr(..)
+ | ty::Never
+ | 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),
- };
+ _ => return Err(CopyImplementationError::NotAnAdt),
+ };
- let mut infringing = Vec::new();
- for variant in adt.variants() {
- for field in &variant.fields {
- let ty = field.ty(tcx, substs);
- if ty.references_error() {
- continue;
- }
- let span = tcx.def_span(field.did);
- // FIXME(compiler-errors): This gives us better spans for bad
- // projection types like in issue-50480.
- // If the ADT has substs, point to the cause we are given.
- // If it does not, then this field probably doesn't normalize
- // to begin with, and point to the bad field's span instead.
- let cause = if field
- .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
- .has_param_types_or_consts()
- {
- parent_cause.clone()
- } else {
- ObligationCause::dummy_with_span(span)
- };
- match traits::fully_normalize(&infcx, cause, param_env, ty) {
- Ok(ty) => {
- if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
- infringing.push((field, ty));
- }
- }
- Err(errors) => {
- infcx.report_fulfillment_errors(&errors, None, false);
- }
- };
+ let mut infringing = Vec::new();
+ for variant in adt.variants() {
+ for field in &variant.fields {
+ let ty = field.ty(tcx, substs);
+ if ty.references_error() {
+ continue;
}
+ let span = tcx.def_span(field.did);
+ // FIXME(compiler-errors): This gives us better spans for bad
+ // projection types like in issue-50480.
+ // If the ADT has substs, point to the cause we are given.
+ // If it does not, then this field probably doesn't normalize
+ // to begin with, and point to the bad field's span instead.
+ let cause = if field
+ .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
+ .has_non_region_param()
+ {
+ parent_cause.clone()
+ } else {
+ ObligationCause::dummy_with_span(span)
+ };
+ match traits::fully_normalize(&infcx, cause, param_env, ty) {
+ Ok(ty) => {
+ if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
+ infringing.push((field, ty));
+ }
+ }
+ Err(errors) => {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ }
+ };
}
- if !infringing.is_empty() {
- return Err(CopyImplementationError::InfrigingFields(infringing));
- }
- if adt.has_dtor(tcx) {
- return Err(CopyImplementationError::HasDestructor);
- }
+ }
+ if !infringing.is_empty() {
+ return Err(CopyImplementationError::InfrigingFields(infringing));
+ }
+ if adt.has_dtor(tcx) {
+ return Err(CopyImplementationError::HasDestructor);
+ }
- Ok(())
- })
+ Ok(())
}
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 40596078f..0bf54c096 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -26,7 +26,7 @@ pub mod wf;
use crate::errors::DumpVTableEntries;
use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::{InferCtxt, TyCtxtInferExt};
-use crate::traits::error_reporting::InferCtxtExt as _;
+use crate::traits::error_reporting::TypeErrCtxtExt as _;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
@@ -34,12 +34,11 @@ use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_infer::traits::TraitEngineExt as _;
use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{
- self, DefIdTree, GenericParamDefKind, Subst, ToPredicate, Ty, TyCtxt, TypeSuperVisitable,
- VtblEntry,
+ self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, VtblEntry,
};
+use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_span::{sym, Span};
use smallvec::SmallVec;
@@ -130,7 +129,7 @@ pub fn predicates_for_generics<'tcx>(
move |(idx, (predicate, span))| Obligation {
cause: cause(idx, span),
recursion_depth: 0,
- param_env: param_env,
+ param_env,
predicate,
},
)
@@ -141,8 +140,8 @@ pub fn predicates_for_generics<'tcx>(
/// `bound` or is not known to meet bound (note that this is
/// conservative towards *no impl*, which is the opposite of the
/// `evaluate` methods).
-pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
def_id: DefId,
@@ -171,7 +170,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
result
);
- if result && ty.has_infer_types_or_consts() {
+ if result && ty.has_non_region_infer() {
// 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
@@ -235,54 +234,51 @@ fn do_normalize_predicates<'tcx>(
// by wfcheck anyway, so I'm not sure we have to check
// them here too, and we will remove this function when
// we move over to lazy normalization *anyway*.
- tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
- let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
- Ok(predicates) => predicates,
- Err(errors) => {
- let reported = infcx.report_fulfillment_errors(&errors, None, false);
- return Err(reported);
- }
- };
+ let infcx = tcx.infer_ctxt().ignoring_regions().build();
+ let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
+ Ok(predicates) => predicates,
+ Err(errors) => {
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ return Err(reported);
+ }
+ };
- debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
+ debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
- // We can use the `elaborated_env` here; the region code only
- // cares about declarations like `'a: 'b`.
- let outlives_env = OutlivesEnvironment::new(elaborated_env);
+ // We can use the `elaborated_env` here; the region code only
+ // cares about declarations like `'a: 'b`.
+ let outlives_env = OutlivesEnvironment::new(elaborated_env);
+
+ // FIXME: It's very weird that we ignore region obligations but apparently
+ // still need to use `resolve_regions` as we need the resolved regions in
+ // the normalized predicates.
+ let errors = infcx.resolve_regions(&outlives_env);
+ if !errors.is_empty() {
+ tcx.sess.delay_span_bug(
+ span,
+ format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"),
+ );
+ }
- // FIXME: It's very weird that we ignore region obligations but apparently
- // still need to use `resolve_regions` as we need the resolved regions in
- // the normalized predicates.
- let errors = infcx.resolve_regions(&outlives_env);
- if !errors.is_empty() {
- tcx.sess.delay_span_bug(
+ match infcx.fully_resolve(predicates) {
+ Ok(predicates) => Ok(predicates),
+ Err(fixup_err) => {
+ // If we encounter a fixup error, it means that some type
+ // variable wound up unconstrained. I actually don't know
+ // if this can happen, and I certainly don't expect it to
+ // happen often, but if it did happen it probably
+ // represents a legitimate failure due to some kind of
+ // unconstrained variable.
+ //
+ // @lcnr: Let's still ICE here for now. I want a test case
+ // for that.
+ span_bug!(
span,
- format!(
- "failed region resolution while normalizing {elaborated_env:?}: {errors:?}"
- ),
+ "inference variables in normalized parameter environment: {}",
+ fixup_err
);
}
-
- match infcx.fully_resolve(predicates) {
- Ok(predicates) => Ok(predicates),
- Err(fixup_err) => {
- // If we encounter a fixup error, it means that some type
- // variable wound up unconstrained. I actually don't know
- // if this can happen, and I certainly don't expect it to
- // happen often, but if it did happen it probably
- // represents a legitimate failure due to some kind of
- // unconstrained variable.
- //
- // @lcnr: Let's still ICE here for now. I want a test case
- // for that.
- span_bug!(
- span,
- "inference variables in normalized parameter environment: {}",
- fixup_err
- );
- }
- }
- })
+ }
}
// FIXME: this is gonna need to be removed ...
@@ -394,8 +390,8 @@ pub fn normalize_param_env_or_error<'tcx>(
}
/// Normalize a type and process all resulting obligations, returning any errors
-pub fn fully_normalize<'a, 'tcx, T>(
- infcx: &InferCtxt<'a, 'tcx>,
+pub fn fully_normalize<'tcx, T>(
+ infcx: &InferCtxt<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
value: T,
@@ -430,8 +426,8 @@ where
/// Process an obligation (and any nested obligations that come from it) to
/// completion, returning any errors
-pub fn fully_solve_obligation<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+pub fn fully_solve_obligation<'tcx>(
+ infcx: &InferCtxt<'tcx>,
obligation: PredicateObligation<'tcx>,
) -> Vec<FulfillmentError<'tcx>> {
let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
@@ -441,8 +437,8 @@ pub fn fully_solve_obligation<'a, 'tcx>(
/// Process a set of obligations (and any nested obligations that come from them)
/// to completion
-pub fn fully_solve_obligations<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+pub fn fully_solve_obligations<'tcx>(
+ infcx: &InferCtxt<'tcx>,
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
) -> Vec<FulfillmentError<'tcx>> {
let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
@@ -453,8 +449,8 @@ pub fn fully_solve_obligations<'a, 'tcx>(
/// Process a bound (and any nested obligations that come from it) to completion.
/// This is a convenience function for traits that have no generic arguments, such
/// as auto traits, and builtin traits like Copy or Sized.
-pub fn fully_solve_bound<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+pub fn fully_solve_bound<'tcx>(
+ infcx: &InferCtxt<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
@@ -474,21 +470,20 @@ pub fn impossible_predicates<'tcx>(
) -> bool {
debug!("impossible_predicates(predicates={:?})", predicates);
- let result = tcx.infer_ctxt().enter(|infcx| {
- let param_env = ty::ParamEnv::reveal_all();
- let ocx = ObligationCtxt::new(&infcx);
- let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates);
- for predicate in predicates {
- let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
- ocx.register_obligation(obligation);
- }
- let errors = ocx.select_all_or_error();
+ let infcx = tcx.infer_ctxt().build();
+ let param_env = ty::ParamEnv::reveal_all();
+ let ocx = ObligationCtxt::new(&infcx);
+ let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates);
+ for predicate in predicates {
+ let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
+ ocx.register_obligation(obligation);
+ }
+ let errors = ocx.select_all_or_error();
- // Clean up after ourselves
- let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+ // Clean up after ourselves
+ let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
- !errors.is_empty()
- });
+ let result = !errors.is_empty();
debug!("impossible_predicates = {:?}", result);
result
}
@@ -579,18 +574,16 @@ fn is_impossible_method<'tcx>(
}
});
- tcx.infer_ctxt().ignoring_regions().enter(|ref infcx| {
- for obligation in predicates_for_trait {
- // Ignore overflow error, to be conservative.
- if let Ok(result) = infcx.evaluate_obligation(&obligation)
- && !result.may_apply()
- {
- return true;
- }
+ let infcx = tcx.infer_ctxt().ignoring_regions().build();
+ for obligation in predicates_for_trait {
+ // Ignore overflow error, to be conservative.
+ if let Ok(result) = infcx.evaluate_obligation(&obligation)
+ && !result.may_apply()
+ {
+ return true;
}
-
- false
- })
+ }
+ false
}
#[derive(Clone, Debug)]
@@ -771,12 +764,9 @@ fn dump_vtable_entries<'tcx>(
});
}
-fn own_existential_vtable_entries<'tcx>(
- tcx: TyCtxt<'tcx>,
- trait_ref: ty::PolyExistentialTraitRef<'tcx>,
-) -> &'tcx [DefId] {
+fn own_existential_vtable_entries<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId) -> &'tcx [DefId] {
let trait_methods = tcx
- .associated_items(trait_ref.def_id())
+ .associated_items(trait_def_id)
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Fn);
// Now list each method's DefId (for within its trait).
@@ -785,7 +775,7 @@ fn own_existential_vtable_entries<'tcx>(
let def_id = trait_method.def_id;
// Some methods cannot be called on an object; skip those.
- if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
+ if !is_vtable_safe_method(tcx, trait_def_id, &trait_method) {
debug!("own_existential_vtable_entry: not vtable safe");
return None;
}
@@ -817,7 +807,7 @@ fn vtable_entries<'tcx>(
// Lookup the shape of vtable for the trait.
let own_existential_entries =
- tcx.own_existential_vtable_entries(existential_trait_ref);
+ tcx.own_existential_vtable_entries(existential_trait_ref.def_id());
let own_entries = own_existential_entries.iter().copied().map(|def_id| {
debug!("vtable_entries: trait_method={:?}", def_id);
@@ -953,10 +943,9 @@ pub fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>(
}),
);
- let implsrc = tcx.infer_ctxt().enter(|infcx| {
- let mut selcx = SelectionContext::new(&infcx);
- selcx.select(&obligation).unwrap()
- });
+ let infcx = tcx.infer_ctxt().build();
+ let mut selcx = SelectionContext::new(&infcx);
+ let implsrc = selcx.select(&obligation).unwrap();
let Some(ImplSource::TraitUpcasting(implsrc_traitcasting)) = implsrc else {
bug!();
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index f2779ce2d..0bb25a74d 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -8,20 +8,20 @@
//! - not reference the erased type `Self` except for in this receiver;
//! - not have generic type parameters.
-use super::elaborate_predicates;
+use super::{elaborate_predicates, elaborate_trait_ref};
use crate::infer::TyCtxtInferExt;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{self, Obligation, ObligationCause};
use hir::def::DefKind;
-use rustc_errors::{FatalError, MultiSpan};
+use rustc_errors::{DelayDm, FatalError, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst};
-use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
use rustc_middle::ty::{
self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
};
+use rustc_middle::ty::{GenericArg, InternalSubsts};
use rustc_middle::ty::{Predicate, ToPredicate};
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
use rustc_span::symbol::Symbol;
@@ -164,37 +164,42 @@ fn lint_object_unsafe_trait(
) {
// Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
// It's also hard to get a use site span, so we use the method definition span.
- tcx.struct_span_lint_hir(WHERE_CLAUSES_OBJECT_SAFETY, hir::CRATE_HIR_ID, span, |lint| {
- let mut err = lint.build(&format!(
- "the trait `{}` cannot be made into an object",
- tcx.def_path_str(trait_def_id)
- ));
- let node = tcx.hir().get_if_local(trait_def_id);
- let mut spans = MultiSpan::from_span(span);
- if let Some(hir::Node::Item(item)) = node {
- spans.push_span_label(item.ident.span, "this trait cannot be made into an object...");
- spans.push_span_label(span, format!("...because {}", violation.error_msg()));
- } else {
- spans.push_span_label(
- span,
- format!(
- "the trait cannot be made into an object because {}",
- violation.error_msg()
- ),
+ tcx.struct_span_lint_hir(
+ WHERE_CLAUSES_OBJECT_SAFETY,
+ hir::CRATE_HIR_ID,
+ span,
+ DelayDm(|| format!("the trait `{}` cannot be made into an object", tcx.def_path_str(trait_def_id))),
+ |err| {
+ let node = tcx.hir().get_if_local(trait_def_id);
+ let mut spans = MultiSpan::from_span(span);
+ if let Some(hir::Node::Item(item)) = node {
+ spans.push_span_label(
+ item.ident.span,
+ "this trait cannot be made into an object...",
+ );
+ spans.push_span_label(span, format!("...because {}", violation.error_msg()));
+ } else {
+ spans.push_span_label(
+ span,
+ format!(
+ "the trait cannot be made into an object because {}",
+ violation.error_msg()
+ ),
+ );
+ };
+ err.span_note(
+ spans,
+ "for a trait to be \"object safe\" it needs to allow building a vtable to allow the \
+ call to be resolvable dynamically; for more information visit \
+ <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
);
- };
- err.span_note(
- spans,
- "for a trait to be \"object safe\" it needs to allow building a vtable to allow the \
- call to be resolvable dynamically; for more information visit \
- <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
- );
- if node.is_some() {
- // Only provide the help if its a local trait, otherwise it's not
- violation.solution(&mut err);
- }
- err.emit();
- });
+ if node.is_some() {
+ // Only provide the help if its a local trait, otherwise it's not
+ violation.solution(err);
+ }
+ err
+ },
+ );
}
fn sized_trait_bound_spans<'tcx>(
@@ -442,19 +447,6 @@ fn virtual_call_violation_for_method<'tcx>(
return Some(MethodViolationCode::Generic);
}
- if tcx
- .predicates_of(method.def_id)
- .predicates
- .iter()
- // A trait object can't claim to live more than the concrete type,
- // so outlives predicates will always hold.
- .cloned()
- .filter(|(p, _)| p.to_opt_type_outlives().is_none())
- .any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred))
- {
- return Some(MethodViolationCode::WhereClauseReferencesSelf);
- }
-
let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
// Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
@@ -533,6 +525,21 @@ fn virtual_call_violation_for_method<'tcx>(
}
}
+ // NOTE: This check happens last, because it results in a lint, and not a
+ // hard error.
+ if tcx
+ .predicates_of(method.def_id)
+ .predicates
+ .iter()
+ // A trait object can't claim to live more than the concrete type,
+ // so outlives predicates will always hold.
+ .cloned()
+ .filter(|(p, _)| p.to_opt_type_outlives().is_none())
+ .any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred))
+ {
+ return Some(MethodViolationCode::WhereClauseReferencesSelf);
+ }
+
None
}
@@ -560,51 +567,44 @@ fn receiver_for_self_ty<'tcx>(
/// Creates the object type for the current trait. For example,
/// if the current trait is `Deref`, then this will be
/// `dyn Deref<Target = Self::Target> + 'static`.
+#[instrument(level = "trace", skip(tcx), ret)]
fn object_ty_for_trait<'tcx>(
tcx: TyCtxt<'tcx>,
trait_def_id: DefId,
lifetime: ty::Region<'tcx>,
) -> Ty<'tcx> {
- debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id);
-
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 mut associated_types = traits::supertraits(tcx, trait_ref)
- .flat_map(|super_trait_ref| {
- tcx.associated_items(super_trait_ref.def_id())
- .in_definition_order()
- .map(move |item| (super_trait_ref, item))
- })
- .filter(|(_, item)| item.kind == ty::AssocKind::Type)
- .collect::<Vec<_>>();
-
- // existential predicates need to be in a specific order
- associated_types.sort_by_cached_key(|(_, item)| tcx.def_path_hash(item.def_id));
-
- let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| {
- // We *can* get bound lifetimes here in cases like
- // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
- super_trait_ref.map_bound(|super_trait_ref| {
- ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
- term: tcx.mk_projection(item.def_id, super_trait_ref.substs).into(),
- item_def_id: item.def_id,
- substs: super_trait_ref.substs,
- })
+ debug!(?trait_predicate);
+
+ let mut elaborated_predicates: Vec<_> = elaborate_trait_ref(tcx, trait_ref)
+ .filter_map(|obligation| {
+ debug!(?obligation);
+ let pred = obligation.predicate.to_opt_poly_projection_pred()?;
+ Some(pred.map_bound(|p| {
+ ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
+ item_def_id: p.projection_ty.item_def_id,
+ substs: p.projection_ty.substs,
+ term: p.term,
+ })
+ }))
})
- });
+ .collect();
+ // NOTE: Since #37965, the existential predicates list has depended on the
+ // list of predicates to be sorted. This is mostly to enforce that the primary
+ // predicate comes first.
+ elaborated_predicates.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
+ elaborated_predicates.dedup();
let existential_predicates = tcx
- .mk_poly_existential_predicates(iter::once(trait_predicate).chain(projection_predicates));
-
- let object_ty = tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn);
-
- debug!("object_ty_for_trait: object_ty=`{}`", object_ty);
+ .mk_poly_existential_predicates(iter::once(trait_predicate).chain(elaborated_predicates));
+ debug!(?existential_predicates);
- object_ty
+ tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn)
}
/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
@@ -729,10 +729,9 @@ fn receiver_is_dispatchable<'tcx>(
Obligation::new(ObligationCause::dummy(), param_env, predicate)
};
- tcx.infer_ctxt().enter(|ref infcx| {
- // the receiver is dispatchable iff the obligation holds
- infcx.predicate_must_hold_modulo_regions(&obligation)
- })
+ let infcx = tcx.infer_ctxt().build();
+ // the receiver is dispatchable iff the obligation holds
+ infcx.predicate_must_hold_modulo_regions(&obligation)
}
fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
@@ -838,21 +837,14 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
}
}
- fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
+ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
// Constants can only influence object safety if they reference `Self`.
// This is only possible for unevaluated constants, so we walk these here.
//
- // If `AbstractConst::new` returned an error we already failed compilation
+ // If `AbstractConst::from_const` returned an error we already failed compilation
// so we don't have to emit an additional error here.
- //
- // We currently recurse into abstract consts here but do not recurse in
- // `is_const_evaluatable`. This means that the object safety check is more
- // liberal than the const eval check.
- //
- // This shouldn't really matter though as we can't really use any
- // constants which are not considered const evaluatable.
use rustc_middle::ty::abstract_const::Node;
- if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) {
+ if let Ok(Some(ct)) = AbstractConst::from_const(self.tcx, ct) {
walk_abstract_const(self.tcx, ct, |node| match node.root(self.tcx) {
Node::Leaf(leaf) => self.visit_const(leaf),
Node::Cast(_, _, ty) => self.visit_ty(ty),
@@ -861,7 +853,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
}
})
} else {
- ControlFlow::CONTINUE
+ ct.super_visit_with(self)
}
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index 3008dfcad..108dae092 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -26,7 +26,7 @@ pub trait InferCtxtExt<'a, 'tcx> {
) -> Bounds<'a, 'tcx>;
}
-impl<'a, 'cx, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'cx, 'tcx> {
+impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
/// Implied bounds are region relationships that we deduce
/// automatically. The idea is that (e.g.) a caller must check that a
/// function's argument types are well-formed immediately before
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index a25fb8543..e4284b9d3 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -18,7 +18,7 @@ use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
-use crate::traits::error_reporting::InferCtxtExt as _;
+use crate::traits::error_reporting::TypeErrCtxtExt as _;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::select::ProjectionMatchesProjection;
use rustc_data_structures::sso::SsoHashSet;
@@ -30,7 +30,6 @@ use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable};
use rustc_middle::ty::DefIdTree;
use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
@@ -63,7 +62,8 @@ enum ProjectionCandidate<'tcx> {
/// From a where-clause in the env or object type
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
- /// From the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C
+ /// From the definition of `Trait` when you have something like
+ /// `<<A as Trait>::B as Trait2>::C`.
TraitDef(ty::PolyProjectionPredicate<'tcx>),
/// Bounds specified on an object type
@@ -72,7 +72,15 @@ enum ProjectionCandidate<'tcx> {
/// From an "impl" (or a "pseudo-impl" returned by select)
Select(Selection<'tcx>),
- ImplTraitInTrait(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>),
+ ImplTraitInTrait(ImplTraitInTraitCandidate<'tcx>),
+}
+
+#[derive(PartialEq, Eq, Debug)]
+enum ImplTraitInTraitCandidate<'tcx> {
+ // The `impl Trait` from a trait function's default body
+ Trait,
+ // A concrete type provided from a trait's `impl Trait` from an impl
+ Impl(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>),
}
enum ProjectionCandidateSet<'tcx> {
@@ -256,7 +264,7 @@ fn project_and_unify_type<'cx, 'tcx>(
};
debug!(?normalized, ?obligations, "project_and_unify_type result");
let actual = obligation.predicate.term;
- // For an example where this is neccessary see src/test/ui/impl-trait/nested-return-type2.rs
+ // For an example where this is necessary see src/test/ui/impl-trait/nested-return-type2.rs
// This allows users to omit re-mentioning all bounds on an associated type and just use an
// `impl Trait` for the assoc type to add more bounds.
let InferOk { value: actual, obligations: new } =
@@ -514,7 +522,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
self.param_env,
ty,
);
- self.selcx.infcx().report_overflow_error(&obligation, true);
+ self.selcx.infcx().err_ctxt().report_overflow_error(&obligation, true);
}
let substs = substs.fold_with(self);
@@ -557,21 +565,6 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
.flatten()
.unwrap_or_else(|| ty.super_fold_with(self).into())
};
- // For cases like #95134 we would like to catch overflows early
- // otherwise they slip away away and cause ICE.
- let recursion_limit = self.tcx().recursion_limit();
- if !recursion_limit.value_within_limit(self.depth)
- // HACK: Don't overflow when running cargo doc see #100991
- && !self.tcx().sess.opts.actually_rustdoc
- {
- let obligation = Obligation::with_depth(
- self.cause.clone(),
- recursion_limit.0,
- self.param_env,
- ty,
- );
- self.selcx.infcx().report_overflow_error(&obligation, true);
- }
debug!(
?self.depth,
?ty,
@@ -664,7 +657,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
}
pub struct BoundVarReplacer<'me, 'tcx> {
- infcx: &'me InferCtxt<'me, 'tcx>,
+ infcx: &'me InferCtxt<'tcx>,
// These three maps track the bound variable that were replaced by placeholders. It might be
// nice to remove these since we already have the `kind` in the placeholder; we really just need
// the `var` (but we *could* bring that into scope if we were to track them as we pass them).
@@ -692,7 +685,7 @@ pub struct BoundVarReplacer<'me, 'tcx> {
/// FIXME(@lcnr): We may even consider experimenting with eagerly replacing bound vars during
/// normalization as well, at which point this function will be unnecessary and can be removed.
pub fn with_replaced_escaping_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>, R: TypeFoldable<'tcx>>(
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
value: T,
f: impl FnOnce(T) -> R,
@@ -718,7 +711,7 @@ impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> {
/// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that
/// use a binding level above `universe_indices.len()`, we fail.
pub fn replace_bound_vars<T: TypeFoldable<'tcx>>(
- infcx: &'me InferCtxt<'me, 'tcx>,
+ infcx: &'me InferCtxt<'tcx>,
universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>,
value: T,
) -> (
@@ -838,7 +831,7 @@ impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
// The inverse of `BoundVarReplacer`: replaces placeholders with the bound vars from which they came.
pub struct PlaceholderReplacer<'me, 'tcx> {
- infcx: &'me InferCtxt<'me, 'tcx>,
+ infcx: &'me InferCtxt<'tcx>,
mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
@@ -848,7 +841,7 @@ pub struct PlaceholderReplacer<'me, 'tcx> {
impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> {
pub fn replace_placeholders<T: TypeFoldable<'tcx>>(
- infcx: &'me InferCtxt<'me, 'tcx>,
+ infcx: &'me InferCtxt<'tcx>,
mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
@@ -1319,6 +1312,19 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
let tcx = selcx.tcx();
if tcx.def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder {
let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id);
+ // If we are trying to project an RPITIT with trait's default `Self` parameter,
+ // then we must be within a default trait body.
+ if obligation.predicate.self_ty()
+ == ty::InternalSubsts::identity_for_item(tcx, obligation.predicate.item_def_id)
+ .type_at(0)
+ && tcx.associated_item(trait_fn_def_id).defaultness(tcx).has_value()
+ {
+ candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(
+ ImplTraitInTraitCandidate::Trait,
+ ));
+ return;
+ }
+
let trait_def_id = tcx.parent(trait_fn_def_id);
let trait_substs =
obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id));
@@ -1330,7 +1336,9 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
let _ =
selcx.infcx().commit_if_ok(|_| match selcx.select(&obligation.with(trait_predicate)) {
Ok(Some(super::ImplSource::UserDefined(data))) => {
- candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data));
+ candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(
+ ImplTraitInTraitCandidate::Impl(data),
+ ));
Ok(())
}
Ok(None) => {
@@ -1368,7 +1376,7 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>(
);
}
-/// In the case of a nested projection like <<A as Foo>::FooT as Bar>::BarT, we may find
+/// In the case of a nested projection like `<<A as Foo>::FooT as Bar>::BarT`, we may find
/// that the definition of `Foo` has some clues:
///
/// ```ignore (illustrative)
@@ -1489,7 +1497,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
candidate_set.push_candidate(ctor(data));
if potentially_unnormalized_candidates
- && !obligation.predicate.has_infer_types_or_consts()
+ && !obligation.predicate.has_non_region_infer()
{
// HACK: Pick the first trait def candidate for a fully
// inferred predicate. This is to allow duplicates that
@@ -1751,8 +1759,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
super::ImplSource::AutoImpl(..)
| super::ImplSource::Builtin(..)
| super::ImplSource::TraitUpcasting(_)
- | super::ImplSource::ConstDestruct(_)
- | super::ImplSource::Tuple => {
+ | super::ImplSource::ConstDestruct(_) => {
// These traits have no associated types.
selcx.tcx().sess.delay_span_bug(
obligation.cause.span,
@@ -1793,9 +1800,18 @@ fn confirm_candidate<'cx, 'tcx>(
ProjectionCandidate::Select(impl_source) => {
confirm_select_candidate(selcx, obligation, impl_source)
}
- ProjectionCandidate::ImplTraitInTrait(data) => {
+ ProjectionCandidate::ImplTraitInTrait(ImplTraitInTraitCandidate::Impl(data)) => {
confirm_impl_trait_in_trait_candidate(selcx, obligation, data)
}
+ // If we're projecting an RPITIT for a default trait body, that's just
+ // the same def-id, but as an opaque type (with regular RPIT semantics).
+ ProjectionCandidate::ImplTraitInTrait(ImplTraitInTraitCandidate::Trait) => Progress {
+ term: selcx
+ .tcx()
+ .mk_opaque(obligation.predicate.item_def_id, obligation.predicate.substs)
+ .into(),
+ obligations: vec![],
+ },
};
// When checking for cycle during evaluation, we compare predicates with
@@ -1830,8 +1846,7 @@ fn confirm_select_candidate<'cx, 'tcx>(
| super::ImplSource::Builtin(..)
| super::ImplSource::TraitUpcasting(_)
| super::ImplSource::TraitAlias(..)
- | super::ImplSource::ConstDestruct(_)
- | super::ImplSource::Tuple => {
+ | super::ImplSource::ConstDestruct(_) => {
// we don't create Select candidates with this kind of resolution
span_bug!(
obligation.cause.span,
@@ -2142,15 +2157,15 @@ fn confirm_impl_candidate<'cx, 'tcx>(
let identity_substs =
crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id);
let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id);
- let kind = ty::ConstKind::Unevaluated(ty::Unevaluated::new(did, identity_substs));
+ let kind = ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new(did, identity_substs));
ty.map_bound(|ty| tcx.mk_const(ty::ConstS { ty, kind }).into())
} else {
ty.map_bound(|ty| ty.into())
};
- if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() {
+ if !check_substs_compatible(tcx, &assoc_ty.item, substs) {
let err = tcx.ty_error_with_message(
obligation.cause.span,
- "impl item and trait item have different parameter counts",
+ "impl item and trait item have different parameters",
);
Progress { term: err.into(), obligations: nested }
} else {
@@ -2159,6 +2174,44 @@ fn confirm_impl_candidate<'cx, 'tcx>(
}
}
+// Verify that the trait item and its implementation have compatible substs lists
+fn check_substs_compatible<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ assoc_ty: &ty::AssocItem,
+ substs: ty::SubstsRef<'tcx>,
+) -> bool {
+ fn check_substs_compatible_inner<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ generics: &'tcx ty::Generics,
+ args: &'tcx [ty::GenericArg<'tcx>],
+ ) -> bool {
+ if generics.count() != args.len() {
+ return false;
+ }
+
+ let (parent_args, own_args) = args.split_at(generics.parent_count);
+
+ if let Some(parent) = generics.parent
+ && let parent_generics = tcx.generics_of(parent)
+ && !check_substs_compatible_inner(tcx, parent_generics, parent_args) {
+ return false;
+ }
+
+ for (param, arg) in std::iter::zip(&generics.params, own_args) {
+ match (&param.kind, arg.unpack()) {
+ (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_))
+ | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_))
+ | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {}
+ _ => return false,
+ }
+ }
+
+ true
+ }
+
+ check_substs_compatible_inner(tcx, tcx.generics_of(assoc_ty.def_id), substs.as_slice())
+}
+
fn confirm_impl_trait_in_trait_candidate<'tcx>(
selcx: &mut SelectionContext<'_, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
@@ -2175,8 +2228,21 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
return Progress { term: tcx.ty_error().into(), obligations };
}
+ // Use the default `impl Trait` for the trait, e.g., for a default trait body
+ if leaf_def.item.container == ty::AssocItemContainer::TraitContainer {
+ return Progress {
+ term: tcx
+ .mk_opaque(obligation.predicate.item_def_id, obligation.predicate.substs)
+ .into(),
+ obligations,
+ };
+ }
+
let impl_fn_def_id = leaf_def.item.def_id;
- let impl_fn_substs = obligation.predicate.substs.rebase_onto(tcx, trait_fn_def_id, data.substs);
+ // Rebase from {trait}::{fn}::{opaque} to {impl}::{fn}::{opaque},
+ // since `data.substs` are the impl substs.
+ let impl_fn_substs =
+ obligation.predicate.substs.rebase_onto(tcx, tcx.parent(trait_fn_def_id), data.substs);
let cause = ObligationCause::new(
obligation.cause.span,
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index 32669e23d..c84f128dd 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -31,7 +31,7 @@ pub trait InferCtxtExt<'tcx> {
) -> EvaluationResult;
}
-impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
/// Evaluates whether the predicate can be satisfied (by any means)
/// in the given `ParamEnv`.
fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool {
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 40acabf62..58e4597b7 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -5,17 +5,16 @@
use crate::infer::at::At;
use crate::infer::canonical::OriginalQueryValues;
use crate::infer::{InferCtxt, InferOk};
-use crate::traits::error_reporting::InferCtxtExt;
+use crate::traits::error_reporting::TypeErrCtxtExt;
use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
use rustc_data_structures::sso::SsoHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::traits::Normalized;
-use rustc_middle::mir;
use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
-use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
+use rustc_span::DUMMY_SP;
use std::ops::ControlFlow;
@@ -155,7 +154,7 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor {
}
struct QueryNormalizer<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
cause: &'cx ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>,
@@ -214,7 +213,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
self.param_env,
ty,
);
- self.infcx.report_overflow_error(&obligation, true);
+ self.infcx.err_ctxt().report_overflow_error(&obligation, true);
}
let generic_ty = self.tcx().bound_type_of(def_id);
@@ -255,7 +254,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
let result = tcx.normalize_projection_ty(c_data)?;
// We don't expect ambiguity.
if result.is_ambiguous() {
- bug!("unexpected ambiguity: {:?} {:?}", c_data, result);
+ // Rustdoc normalizes possibly not well-formed types, so only
+ // treat this as a bug if we're not in rustdoc.
+ if !tcx.sess.opts.actually_rustdoc {
+ tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ format!("unexpected ambiguity: {:?} {:?}", c_data, result),
+ );
+ }
+ return Err(NoSolution);
}
let InferOk { value: result, obligations } =
self.infcx.instantiate_query_response_and_region_obligations(
@@ -298,7 +305,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
let result = tcx.normalize_projection_ty(c_data)?;
// We don't expect ambiguity.
if result.is_ambiguous() {
- bug!("unexpected ambiguity: {:?} {:?}", c_data, result);
+ // Rustdoc normalizes possibly not well-formed types, so only
+ // treat this as a bug if we're not in rustdoc.
+ if !tcx.sess.opts.actually_rustdoc {
+ tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ format!("unexpected ambiguity: {:?} {:?}", c_data, result),
+ );
+ }
+ return Err(NoSolution);
}
let InferOk { value: result, obligations } =
self.infcx.instantiate_query_response_and_region_obligations(
@@ -348,31 +363,6 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
))
}
- fn try_fold_mir_const(
- &mut self,
- constant: mir::ConstantKind<'tcx>,
- ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
- Ok(match constant {
- mir::ConstantKind::Ty(c) => {
- let const_folded = c.try_super_fold_with(self)?;
- match const_folded.kind() {
- ty::ConstKind::Value(valtree) => {
- let tcx = self.infcx.tcx;
- let ty = const_folded.ty();
- let const_val = tcx.valtree_to_const_val((ty, valtree));
- debug!(?ty, ?valtree, ?const_val);
-
- mir::ConstantKind::Val(const_val, ty)
- }
- _ => mir::ConstantKind::Ty(const_folded),
- }
- }
- mir::ConstantKind::Val(_, _) | mir::ConstantKind::Unevaluated(..) => {
- constant.try_super_fold_with(self)?
- }
- })
- }
-
#[inline]
fn try_fold_predicate(
&mut self,
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 18988861a..6bf3ed0d0 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
@@ -16,7 +16,7 @@ pub struct CustomTypeOp<F, G> {
impl<F, G> CustomTypeOp<F, G> {
pub fn new<'tcx, R>(closure: F, description: G) -> Self
where
- F: FnOnce(&InferCtxt<'_, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
+ F: FnOnce(&InferCtxt<'tcx>) -> Fallible<InferOk<'tcx, R>>,
G: Fn() -> String,
{
CustomTypeOp { closure, description }
@@ -25,7 +25,7 @@ impl<F, G> CustomTypeOp<F, G> {
impl<'tcx, F, R: fmt::Debug, G> super::TypeOp<'tcx> for CustomTypeOp<F, G>
where
- F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
+ F: for<'a, 'cx> FnOnce(&'a InferCtxt<'tcx>) -> Fallible<InferOk<'tcx, R>>,
G: Fn() -> String,
{
type Output = R;
@@ -36,7 +36,7 @@ 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>) -> Fallible<TypeOpOutput<'tcx, Self>> {
if cfg!(debug_assertions) {
info!("fully_perform({:?})", self);
}
@@ -57,7 +57,7 @@ where
/// Executes `op` and then scrapes out all the "old style" region
/// constraints that result, creating query-region-constraints.
pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> {
// During NLL, we expect that nobody will register region
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 8a7916570..29ae8ae6b 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
@@ -32,7 +32,7 @@ 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>) -> Fallible<TypeOpOutput<'tcx, Self>>;
}
/// The output from performing a type op
@@ -78,7 +78,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx {
fn fully_perform_into(
query_key: ParamEnvAnd<'tcx, Self>,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
) -> Fallible<(
Self::QueryResponse,
@@ -120,7 +120,7 @@ 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>) -> Fallible<TypeOpOutput<'tcx, Self>> {
let mut region_constraints = QueryRegionConstraints::default();
let (output, error_info, mut obligations, _) =
Q::fully_perform_into(self, infcx, &mut region_constraints)?;
diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs
index 8148e2b78..8cf500a46 100644
--- a/compiler/rustc_trait_selection/src/traits/relationships.rs
+++ b/compiler/rustc_trait_selection/src/traits/relationships.rs
@@ -6,7 +6,7 @@ use rustc_middle::ty::{self, ToPredicate};
pub(crate) fn update<'tcx, T>(
engine: &mut T,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
obligation: &PredicateObligation<'tcx>,
) where
T: TraitEngine<'tcx>,
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 a80527f63..4c5bc3339 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -6,6 +6,7 @@
//!
//! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
use hir::LangItem;
+use rustc_errors::DelayDm;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::traits::ObligationCause;
@@ -173,7 +174,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?stack, ?candidates, "winnowed to {} candidates", candidates.len());
- let needs_infer = stack.obligation.predicate.has_infer_types_or_consts();
+ let needs_infer = stack.obligation.predicate.has_non_region_infer();
// If there are STILL multiple candidates, we can further
// reduce the list by dropping duplicates -- including
@@ -362,7 +363,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.infcx
.probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
- candidates.vec.extend(result.into_iter().map(ProjectionCandidate));
+ candidates
+ .vec
+ .extend(result.into_iter().map(|(idx, constness)| ProjectionCandidate(idx, constness)));
}
/// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller
@@ -622,7 +625,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
- _ => candidates.vec.push(AutoImplCandidate(def_id)),
+ _ => candidates.vec.push(AutoImplCandidate),
}
}
}
@@ -823,13 +826,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
DEREF_INTO_DYN_SUPERTRAIT,
obligation.cause.body_id,
obligation.cause.span,
- |lint| {
- lint.build(&format!(
- "`{}` implements `Deref` with supertrait `{}` as output",
- source,
- deref_output_ty
- )).emit();
- },
+ DelayDm(|| format!(
+ "`{}` implements `Deref` with supertrait `{}` as output",
+ source, deref_output_ty
+ )),
+ |lint| lint,
);
return;
}
@@ -888,11 +889,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) {
- if obligation.has_param_types_or_consts() {
+ if obligation.has_non_region_param() {
return;
}
- if obligation.has_infer_types_or_consts() {
+ if obligation.has_non_region_infer() {
candidates.ambiguous = true;
return;
}
@@ -913,7 +914,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let def_id = obligation.predicate.def_id();
if self.tcx().is_trait_alias(def_id) {
- candidates.vec.push(TraitAliasCandidate(def_id));
+ candidates.vec.push(TraitAliasCandidate);
}
}
@@ -1020,7 +1021,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let self_ty = self.infcx().shallow_resolve(obligation.self_ty().skip_binder());
match self_ty.kind() {
ty::Tuple(_) => {
- candidates.vec.push(TupleCandidate);
+ candidates.vec.push(BuiltinCandidate { has_nested: false });
}
ty::Infer(ty::TyVar(_)) => {
candidates.ambiguous = true;
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index d1deef784..ed22058c6 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -11,9 +11,10 @@ use rustc_hir::lang_items::LangItem;
use rustc_index::bit_set::GrowableBitSet;
use rustc_infer::infer::InferOk;
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt};
-use rustc_middle::ty::{ToPolyTraitRef, ToPredicate};
+use rustc_middle::ty::{
+ self, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef,
+ ToPolyTraitRef, ToPredicate, Ty, TyCtxt,
+};
use rustc_span::def_id::DefId;
use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
@@ -63,15 +64,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id))
}
- AutoImplCandidate(trait_def_id) => {
- let data = self.confirm_auto_impl_candidate(obligation, trait_def_id);
+ AutoImplCandidate => {
+ let data = self.confirm_auto_impl_candidate(obligation);
ImplSource::AutoImpl(data)
}
- ProjectionCandidate(idx) => {
+ ProjectionCandidate(idx, constness) => {
let obligations = self.confirm_projection_candidate(obligation, idx)?;
- // FIXME(jschievink): constness
- ImplSource::Param(obligations, ty::BoundConstness::NotConst)
+ ImplSource::Param(obligations, constness)
}
ObjectCandidate(idx) => {
@@ -100,8 +100,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
PointeeCandidate => ImplSource::Pointee(ImplSourcePointeeData),
- TraitAliasCandidate(alias_def_id) => {
- let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
+ TraitAliasCandidate => {
+ let data = self.confirm_trait_alias_candidate(obligation);
ImplSource::TraitAlias(data)
}
@@ -126,8 +126,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let data = self.confirm_const_destruct_candidate(obligation, def_id)?;
ImplSource::ConstDestruct(data)
}
-
- TupleCandidate => ImplSource::Tuple,
};
if !obligation.predicate.is_const_if_const() {
@@ -290,8 +288,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let scope = type_at(2).skip_binder();
- let assume =
- rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, const_at(3));
+ let Some(assume) =
+ rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, const_at(3)) else {
+ return Err(Unimplemented);
+ };
let cause = obligation.cause.clone();
@@ -315,13 +315,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_auto_impl_candidate(
&mut self,
obligation: &TraitObligation<'tcx>,
- trait_def_id: DefId,
) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> {
- debug!(?obligation, ?trait_def_id, "confirm_auto_impl_candidate");
+ debug!(?obligation, "confirm_auto_impl_candidate");
let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty());
let types = self.constituent_types_for_ty(self_ty);
- self.vtable_auto_impl(obligation, trait_def_id, types)
+ self.vtable_auto_impl(obligation, obligation.predicate.def_id(), types)
}
/// See `confirm_auto_impl_candidate`.
@@ -619,17 +618,47 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
)
.map_bound(|(trait_ref, _)| trait_ref);
- let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+ let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+
+ // Confirm the `type Output: Sized;` bound that is present on `FnOnce`
+ let cause = obligation.derived_cause(BuiltinDerivedObligation);
+ // The binder on the Fn obligation is "less" important than the one on
+ // the signature, as evidenced by how we treat it during projection.
+ // The safe thing to do here is to liberate it, though, which should
+ // have no worse effect than skipping the binder here.
+ let liberated_fn_ty =
+ self.infcx.replace_bound_vars_with_placeholders(obligation.predicate.rebind(self_ty));
+ let output_ty = self
+ .infcx
+ .replace_bound_vars_with_placeholders(liberated_fn_ty.fn_sig(self.tcx()).output());
+ let output_ty = normalize_with_depth_to(
+ self,
+ obligation.param_env,
+ cause.clone(),
+ obligation.recursion_depth,
+ output_ty,
+ &mut nested,
+ );
+ let tr = ty::Binder::dummy(ty::TraitRef::new(
+ self.tcx().require_lang_item(LangItem::Sized, None),
+ self.tcx().mk_substs_trait(output_ty, &[]),
+ ));
+ nested.push(Obligation::new(
+ cause,
+ obligation.param_env,
+ tr.to_poly_trait_predicate().to_predicate(self.tcx()),
+ ));
+
Ok(ImplSourceFnPointerData { fn_ty: self_ty, nested })
}
fn confirm_trait_alias_candidate(
&mut self,
obligation: &TraitObligation<'tcx>,
- alias_def_id: DefId,
) -> ImplSourceTraitAliasData<'tcx, PredicateObligation<'tcx>> {
- debug!(?obligation, ?alias_def_id, "confirm_trait_alias_candidate");
+ debug!(?obligation, "confirm_trait_alias_candidate");
+ let alias_def_id = obligation.predicate.def_id();
let predicate = self.infcx().replace_bound_vars_with_placeholders(obligation.predicate);
let trait_ref = predicate.trait_ref;
let trait_def_id = trait_ref.def_id;
@@ -1196,6 +1225,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Never
| ty::Foreign(_) => {}
+ // `ManuallyDrop` is trivially drop
+ ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().manually_drop() => {}
+
// These types are built-in, so we can fast-track by registering
// nested predicates for their constituent type(s)
ty::Array(ty, _) | ty::Slice(ty) => {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 75bd2c89f..9ebff4892 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -20,7 +20,7 @@ use super::{
};
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
-use crate::traits::error_reporting::InferCtxtExt;
+use crate::traits::error_reporting::TypeErrCtxtExt;
use crate::traits::project::ProjectAndUnifyResult;
use crate::traits::project::ProjectionCacheKeyExt;
use crate::traits::ProjectionCacheKey;
@@ -35,9 +35,8 @@ use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::fold::BottomUpFolder;
-use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::relate::TypeRelation;
-use rustc_middle::ty::subst::{Subst, SubstsRef};
+use rustc_middle::ty::SubstsRef;
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable};
use rustc_span::symbol::sym;
@@ -94,7 +93,7 @@ impl IntercrateAmbiguityCause {
}
pub struct SelectionContext<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
/// Freshener used specifically for entries on the obligation
/// stack. This ensures that all entries on the stack at one time
@@ -215,7 +214,7 @@ enum BuiltinImplConditions<'tcx> {
}
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
- pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
+ pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
SelectionContext {
infcx,
freshener: infcx.freshener_keep_static(),
@@ -225,28 +224,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
- pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
- SelectionContext {
- infcx,
- freshener: infcx.freshener_keep_static(),
- intercrate: true,
- intercrate_ambiguity_causes: None,
- query_mode: TraitQueryMode::Standard,
- }
+ pub fn intercrate(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> {
+ SelectionContext { intercrate: true, ..SelectionContext::new(infcx) }
}
pub fn with_query_mode(
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
query_mode: TraitQueryMode,
) -> SelectionContext<'cx, 'tcx> {
debug!(?query_mode, "with_query_mode");
- SelectionContext {
- infcx,
- freshener: infcx.freshener_keep_static(),
- intercrate: false,
- intercrate_ambiguity_causes: None,
- query_mode,
- }
+ SelectionContext { query_mode, ..SelectionContext::new(infcx) }
}
/// Enables tracking of intercrate ambiguity causes. See
@@ -266,7 +253,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.intercrate_ambiguity_causes.take().unwrap_or_default()
}
- pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'tcx> {
+ pub fn infcx(&self) -> &'cx InferCtxt<'tcx> {
self.infcx
}
@@ -689,19 +676,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
ty::PredicateKind::ConstEquate(c1, c2) => {
+ assert!(
+ self.tcx().features().generic_const_exprs,
+ "`ConstEquate` without a feature gate: {c1:?} {c2:?}",
+ );
debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts");
- if self.tcx().features().generic_const_exprs {
- // FIXME: we probably should only try to unify abstract constants
- // if the constants depend on generic parameters.
- //
- // Let's just see where this breaks :shrug:
- if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
- (c1.kind(), c2.kind())
- {
- if self.infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
- return Ok(EvaluatedToOk);
- }
+ // FIXME: we probably should only try to unify abstract constants
+ // if the constants depend on generic parameters.
+ //
+ // Let's just see where this breaks :shrug:
+ if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
+ (c1.kind(), c2.kind())
+ {
+ if self.infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
+ return Ok(EvaluatedToOk);
}
}
@@ -741,7 +730,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
)
}
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
- if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() {
+ if c1.has_non_region_infer() || c2.has_non_region_infer() {
Ok(EvaluatedToAmbig)
} else {
// Two different constants using generic parameters ~> error.
@@ -839,7 +828,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// must be met of course). One obvious case this comes up is
/// marker traits like `Send`. Think of a linked list:
///
- /// struct List<T> { data: T, next: Option<Box<List<T>>> }
+ /// struct List<T> { data: T, next: Option<Box<List<T>>> }
///
/// `Box<List<T>>` will be `Send` if `T` is `Send` and
/// `Option<Box<List<T>>>` is `Send`, and in turn
@@ -926,38 +915,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let unbound_input_types =
stack.fresh_trait_pred.skip_binder().trait_ref.substs.types().any(|ty| ty.is_fresh());
- if stack.obligation.polarity() != ty::ImplPolarity::Negative {
- // This check was an imperfect workaround for a bug in the old
- // intercrate mode; it should be removed when that goes away.
- if unbound_input_types && self.intercrate {
- debug!("evaluate_stack --> unbound argument, intercrate --> ambiguous",);
- // Heuristics: show the diagnostics when there are no candidates in crate.
- if self.intercrate_ambiguity_causes.is_some() {
- debug!("evaluate_stack: intercrate_ambiguity_causes is some");
- if let Ok(candidate_set) = self.assemble_candidates(stack) {
- if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
- let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
- let self_ty = trait_ref.self_ty();
- let cause = with_no_trimmed_paths!({
- IntercrateAmbiguityCause::DownstreamCrate {
- trait_desc: trait_ref.print_only_trait_path().to_string(),
- self_desc: if self_ty.has_concrete_skeleton() {
- Some(self_ty.to_string())
- } else {
- None
- },
- }
- });
-
- debug!(?cause, "evaluate_stack: pushing cause");
- self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause);
- }
- }
- }
- return Ok(EvaluatedToAmbig);
- }
- }
-
if unbound_input_types
&& stack.iter().skip(1).any(|prev| {
stack.obligation.param_env == prev.obligation.param_env
@@ -1140,7 +1097,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ErrorGuaranteed::unchecked_claim_error_was_emitted(),
));
}
- self.infcx.report_overflow_error(error_obligation, true);
+ self.infcx.err_ctxt().report_overflow_error(error_obligation, true);
}
TraitQueryMode::Canonical => {
return Err(OverflowError::Canonical);
@@ -1192,8 +1149,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplCandidate(def_id) if tcx.constness(def_id) == hir::Constness::Const => {}
// const param
ParamCandidate(trait_pred) if trait_pred.is_const_if_const() => {}
+ // const projection
+ ProjectionCandidate(_, ty::BoundConstness::ConstIfConst) => {}
// auto trait impl
- AutoImplCandidate(..) => {}
+ AutoImplCandidate => {}
// generator, this will raise error in other places
// or ignore error with const_async_blocks feature
GeneratorCandidate => {}
@@ -1399,7 +1358,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn match_projection_obligation_against_definition_bounds(
&mut self,
obligation: &TraitObligation<'tcx>,
- ) -> smallvec::SmallVec<[usize; 2]> {
+ ) -> smallvec::SmallVec<[(usize, ty::BoundConstness); 2]> {
let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate);
let placeholder_trait_predicate =
self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate);
@@ -1447,7 +1406,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
_ => false,
}
}) {
- return Some(idx);
+ return Some((idx, pred.constness));
}
}
None
@@ -1563,7 +1522,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if !generics.params.is_empty()
&& obligation.predicate.substs[generics.parent_count..]
.iter()
- .any(|&p| p.has_infer_types_or_consts() && self.infcx.shallow_resolve(p) != p)
+ .any(|&p| p.has_non_region_infer() && self.infcx.shallow_resolve(p) != p)
{
ProjectionMatchesProjection::Ambiguous
} else {
@@ -1605,13 +1564,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
};
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
- // `DiscriminantKindCandidate`, `ConstDestructCandidate`, and `TupleCandidate`
+ // `DiscriminantKindCandidate`, `ConstDestructCandidate`
// to anything else.
//
// This is a fix for #53123 and prevents winnowing from accidentally extending the
// lifetime of a variable.
match (&other.candidate, &victim.candidate) {
- (_, AutoImplCandidate(..)) | (AutoImplCandidate(..), _) => {
+ (_, AutoImplCandidate) | (AutoImplCandidate, _) => {
bug!(
"default implementations shouldn't be recorded \
when there are other valid candidates"
@@ -1626,8 +1585,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
BuiltinCandidate { has_nested: false }
| DiscriminantKindCandidate
| PointeeCandidate
- | ConstDestructCandidate(_)
- | TupleCandidate,
+ | ConstDestructCandidate(_),
_,
) => true,
(
@@ -1635,8 +1593,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
BuiltinCandidate { has_nested: false }
| DiscriminantKindCandidate
| PointeeCandidate
- | ConstDestructCandidate(_)
- | TupleCandidate,
+ | ConstDestructCandidate(_),
) => false,
(ParamCandidate(other), ParamCandidate(victim)) => {
@@ -1681,11 +1638,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
- | TraitAliasCandidate(..)
+ | TraitAliasCandidate
| ObjectCandidate(_)
- | ProjectionCandidate(_),
+ | ProjectionCandidate(..),
) => !is_global(cand),
- (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
+ (ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref cand)) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
is_global(cand)
@@ -1699,7 +1656,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { has_nested: true }
- | TraitAliasCandidate(..),
+ | TraitAliasCandidate,
ParamCandidate(ref cand),
) => {
// Prefer these to a global where-clause bound
@@ -1707,20 +1664,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
is_global(cand) && other.evaluation.must_apply_modulo_regions()
}
- (ProjectionCandidate(i), ProjectionCandidate(j))
+ (ProjectionCandidate(i, _), ProjectionCandidate(j, _))
| (ObjectCandidate(i), ObjectCandidate(j)) => {
// Arbitrarily pick the lower numbered candidate for backwards
// compatibility reasons. Don't let this affect inference.
i < j && !needs_infer
}
- (ObjectCandidate(_), ProjectionCandidate(_))
- | (ProjectionCandidate(_), ObjectCandidate(_)) => {
+ (ObjectCandidate(_), ProjectionCandidate(..))
+ | (ProjectionCandidate(..), ObjectCandidate(_)) => {
bug!("Have both object and projection candidate")
}
// Arbitrarily give projection and object candidates priority.
(
- ObjectCandidate(_) | ProjectionCandidate(_),
+ ObjectCandidate(_) | ProjectionCandidate(..),
ImplCandidate(..)
| ClosureCandidate
| GeneratorCandidate
@@ -1729,7 +1686,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
- | TraitAliasCandidate(..),
+ | TraitAliasCandidate,
) => true,
(
@@ -1741,18 +1698,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
- | TraitAliasCandidate(..),
- ObjectCandidate(_) | ProjectionCandidate(_),
+ | TraitAliasCandidate,
+ ObjectCandidate(_) | ProjectionCandidate(..),
) => false,
(&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
// See if we can toss out `victim` based on specialization.
- // This requires us to know *for sure* that the `other` impl applies
- // i.e., `EvaluatedToOk`.
+ // While this requires us to know *for sure* that the `other` impl applies
+ // we still use modulo regions here.
//
- // FIXME(@lcnr): Using `modulo_regions` here seems kind of scary
- // to me but is required for `std` to compile, so I didn't change it
- // for now.
+ // This is fine as specialization currently assumes that specializing
+ // impls have to be always applicable, meaning that the only allowed
+ // region constraints may be constraints also present on the default impl.
let tcx = self.tcx();
if other.evaluation.must_apply_modulo_regions() {
if tcx.specializes((other_def, victim_def)) {
@@ -1822,7 +1779,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { has_nested: true }
- | TraitAliasCandidate(..),
+ | TraitAliasCandidate,
ImplCandidate(_)
| ClosureCandidate
| GeneratorCandidate
@@ -1831,7 +1788,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { has_nested: true }
- | TraitAliasCandidate(..),
+ | TraitAliasCandidate,
) => false,
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 7d299e30a..c89165858 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -17,10 +17,10 @@ use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use crate::traits::select::IntercrateAmbiguityCause;
use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
-use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder};
+use rustc_errors::{struct_span_err, DiagnosticBuilder, EmissionGuarantee};
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::{self, ImplSubject, TyCtxt};
+use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
use rustc_span::{Span, DUMMY_SP};
@@ -73,8 +73,8 @@ pub struct OverlapError {
/// through associated type projection. We deal with such cases by using
/// *fulfillment* to relate the two impls, requiring that all projections are
/// resolved.
-pub fn translate_substs<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+pub fn translate_substs<'tcx>(
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
source_impl: DefId,
source_substs: SubstsRef<'tcx>,
@@ -149,13 +149,9 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
// Create an infcx, taking the predicates of impl1 as assumptions:
- tcx.infer_ctxt().enter(|infcx| {
- let impl1_trait_ref = match traits::fully_normalize(
- &infcx,
- ObligationCause::dummy(),
- penv,
- impl1_trait_ref,
- ) {
+ 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(
@@ -166,9 +162,8 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
}
};
- // Attempt to prove that impl2 applies, given all of the above.
- fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
- })
+ // Attempt to prove that impl2 applies, given all of the above.
+ fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
}
/// Attempt to fulfill all obligations of `target_impl` after unification with
@@ -176,8 +171,8 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
/// generics of `target_impl`, including both those needed to unify with
/// `source_trait_ref` and those whose identity is determined via a where
/// clause in the impl.
-fn fulfill_implication<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+fn fulfill_implication<'tcx>(
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
source_trait_ref: ty::TraitRef<'tcx>,
target_impl: DefId,
@@ -350,26 +345,12 @@ fn report_conflicting_impls(
// Work to be done after we've built the DiagnosticBuilder. We have to define it
// now because the struct_lint methods don't return back the DiagnosticBuilder
// that's passed in.
- fn decorate<G: EmissionGuarantee>(
+ fn decorate<'a, 'b, G: EmissionGuarantee>(
tcx: TyCtxt<'_>,
overlap: OverlapError,
- used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
impl_span: Span,
- err: LintDiagnosticBuilder<'_, G>,
- ) -> G {
- let msg = format!(
- "conflicting implementations of trait `{}`{}{}",
- overlap.trait_desc,
- overlap
- .self_desc
- .clone()
- .map_or_else(String::new, |ty| { format!(" for type `{}`", ty) }),
- match used_to_be_allowed {
- Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",
- _ => "",
- }
- );
- let mut err = err.build(&msg);
+ err: &'b mut DiagnosticBuilder<'a, G>,
+ ) -> &'b mut DiagnosticBuilder<'a, G> {
match tcx.span_of_impl(overlap.with_impl) {
Ok(span) => {
err.span_label(span, "first implementation here");
@@ -384,7 +365,9 @@ fn report_conflicting_impls(
}
Err(cname) => {
let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
- Some(s) => format!("conflicting implementation in crate `{}`:\n- {}", cname, s),
+ Some(s) => {
+ format!("conflicting implementation in crate `{}`:\n- {}", cname, s)
+ }
None => format!("conflicting implementation in crate `{}`", cname),
};
err.note(&msg);
@@ -392,28 +375,33 @@ fn report_conflicting_impls(
}
for cause in &overlap.intercrate_ambiguity_causes {
- cause.add_intercrate_ambiguity_hint(&mut err);
+ cause.add_intercrate_ambiguity_hint(err);
}
if overlap.involves_placeholder {
- coherence::add_placeholder_note(&mut err);
+ coherence::add_placeholder_note(err);
}
- err.emit()
+ err
}
+ let msg = format!(
+ "conflicting implementations of trait `{}`{}{}",
+ overlap.trait_desc,
+ overlap.self_desc.as_deref().map_or_else(String::new, |ty| format!(" for type `{ty}`")),
+ match used_to_be_allowed {
+ Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",
+ _ => "",
+ }
+ );
+
match used_to_be_allowed {
None => {
let reported = if overlap.with_impl.is_local()
|| tcx.orphan_check_impl(impl_def_id).is_ok()
{
- let err = struct_span_err!(tcx.sess, impl_span, E0119, "");
- Some(decorate(
- tcx,
- overlap,
- used_to_be_allowed,
- impl_span,
- LintDiagnosticBuilder::new(err),
- ))
+ let mut err = struct_span_err!(tcx.sess, impl_span, E0119, "{msg}",);
+ decorate(tcx, overlap, impl_span, &mut err);
+ Some(err.emit())
} else {
Some(tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check"))
};
@@ -428,9 +416,8 @@ fn report_conflicting_impls(
lint,
tcx.hir().local_def_id_to_hir_id(impl_def_id),
impl_span,
- |ldb| {
- decorate(tcx, overlap, used_to_be_allowed, impl_span, ldb);
- },
+ msg,
+ |err| decorate(tcx, overlap, impl_span, err),
);
}
};
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index fcb73b43f..63f89a33e 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -137,9 +137,8 @@ impl ChildrenExt<'_> for Children {
impl_def_id,
traits::SkipLeakCheck::default(),
overlap_mode,
- |_| true,
- || false,
- );
+ )
+ .is_some();
let error = create_overlap_error(overlap);
@@ -162,34 +161,29 @@ impl ChildrenExt<'_> for Children {
impl_def_id,
traits::SkipLeakCheck::Yes,
overlap_mode,
- |overlap| {
- if let Some(overlap_kind) =
- tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling)
- {
- match overlap_kind {
- ty::ImplOverlapKind::Permitted { marker: _ } => {}
- ty::ImplOverlapKind::Issue33140 => {
- *last_lint_mut = Some(FutureCompatOverlapError {
- error: create_overlap_error(overlap),
- kind: FutureCompatOverlapErrorKind::Issue33140,
- });
- }
+ )
+ .map_or(Ok((false, false)), |overlap| {
+ if let Some(overlap_kind) =
+ tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling)
+ {
+ match overlap_kind {
+ ty::ImplOverlapKind::Permitted { marker: _ } => {}
+ ty::ImplOverlapKind::Issue33140 => {
+ *last_lint_mut = Some(FutureCompatOverlapError {
+ error: create_overlap_error(overlap),
+ kind: FutureCompatOverlapErrorKind::Issue33140,
+ });
}
-
- return Ok((false, false));
}
- let le = tcx.specializes((impl_def_id, possible_sibling));
- let ge = tcx.specializes((possible_sibling, impl_def_id));
+ return Ok((false, false));
+ }
- if le == ge {
- report_overlap_error(overlap, last_lint_mut)
- } else {
- Ok((le, ge))
- }
- },
- || Ok((false, false)),
- )?;
+ let le = tcx.specializes((impl_def_id, possible_sibling));
+ let ge = tcx.specializes((possible_sibling, impl_def_id));
+
+ if le == ge { report_overlap_error(overlap, last_lint_mut) } else { Ok((le, ge)) }
+ })?;
if le && !ge {
debug!(
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index 5829a0f92..932dbbb81 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -68,7 +68,7 @@ pub fn search_for_adt_const_param_violation<'tcx>(
/// Note that this does *not* recursively check if the substructure of `adt_ty`
/// implements the traits.
fn type_marked_structural<'tcx>(
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
adt_ty: Ty<'tcx>,
cause: ObligationCause<'tcx>,
) -> bool {
@@ -265,9 +265,8 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
pub fn provide(providers: &mut Providers) {
providers.has_structural_eq_impls = |tcx, ty| {
- tcx.infer_ctxt().enter(|infcx| {
- let cause = ObligationCause::dummy();
- type_marked_structural(&infcx, ty, cause)
- })
+ let infcx = tcx.infer_ctxt().build();
+ let cause = ObligationCause::dummy();
+ type_marked_structural(&infcx, ty, cause)
};
}
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 0f5dff01c..ed47d2f83 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -5,8 +5,8 @@ use smallvec::SmallVec;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{GenericArg, SubstsRef};
use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
pub use rustc_infer::traits::{self, util::*};
@@ -268,10 +268,7 @@ pub fn count_own_vtable_entries<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
) -> usize {
- let existential_trait_ref =
- trait_ref.map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
- let existential_trait_ref = tcx.erase_regions(existential_trait_ref);
- tcx.own_existential_vtable_entries(existential_trait_ref).len()
+ tcx.own_existential_vtable_entries(trait_ref.def_id()).len()
}
/// Given an upcast trait object described by `object`, returns the
@@ -282,15 +279,10 @@ pub fn get_vtable_index_of_object_method<'tcx, N>(
object: &super::ImplSourceObjectData<'tcx, N>,
method_def_id: DefId,
) -> Option<usize> {
- let existential_trait_ref = object
- .upcast_trait_ref
- .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
- let existential_trait_ref = tcx.erase_regions(existential_trait_ref);
-
// 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(existential_trait_ref)
+ .own_existential_vtable_entries(object.upcast_trait_ref.def_id())
.iter()
.copied()
.position(|def_id| def_id == method_def_id)
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 5ea28fb47..fc0a9f690 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -14,8 +14,8 @@ use std::iter;
/// inference variable, returns `None`, because we are not able to
/// make any progress at all. This is to prevent "livelock" where we
/// say "$0 is WF if $0 is WF".
-pub fn obligations<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+pub fn obligations<'tcx>(
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
recursion_depth: usize,
@@ -79,8 +79,8 @@ pub fn obligations<'a, 'tcx>(
/// well-formed. For example, if there is a trait `Set` defined like
/// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF
/// if `Bar: Eq`.
-pub fn trait_obligations<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+pub fn trait_obligations<'tcx>(
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
trait_pred: &ty::TraitPredicate<'tcx>,
@@ -102,8 +102,8 @@ pub fn trait_obligations<'a, 'tcx>(
}
#[instrument(skip(infcx), ret)]
-pub fn predicate_obligations<'a, 'tcx>(
- infcx: &InferCtxt<'a, 'tcx>,
+pub fn predicate_obligations<'tcx>(
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
predicate: ty::Predicate<'tcx>,
@@ -148,13 +148,8 @@ pub fn predicate_obligations<'a, 'tcx>(
wf.compute(a.into());
wf.compute(b.into());
}
- ty::PredicateKind::ConstEvaluatable(uv) => {
- let obligations = wf.nominal_obligations(uv.def.did, uv.substs);
- wf.out.extend(obligations);
-
- for arg in uv.substs.iter() {
- wf.compute(arg);
- }
+ ty::PredicateKind::ConstEvaluatable(ct) => {
+ wf.compute(ct.into());
}
ty::PredicateKind::ConstEquate(c1, c2) => {
wf.compute(c1.into());
@@ -219,12 +214,14 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
trait_ref, item, cause, pred
);
let (items, impl_def_id) = match item {
- Some(hir::Item { kind: hir::ItemKind::Impl(impl_), def_id, .. }) => (impl_.items, *def_id),
+ Some(hir::Item { kind: hir::ItemKind::Impl(impl_), owner_id, .. }) => {
+ (impl_.items, *owner_id)
+ }
_ => return,
};
let fix_span =
|impl_item_ref: &hir::ImplItemRef| match tcx.hir().impl_item(impl_item_ref.id).kind {
- hir::ImplItemKind::Const(ty, _) | hir::ImplItemKind::TyAlias(ty) => ty.span,
+ hir::ImplItemKind::Const(ty, _) | hir::ImplItemKind::Type(ty) => ty.span,
_ => impl_item_ref.span,
};
@@ -241,7 +238,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id)
&& let Some(impl_item_span) = items
.iter()
- .find(|item| item.id.def_id.to_def_id() == impl_item_id)
+ .find(|item| item.id.owner_id.to_def_id() == impl_item_id)
.map(fix_span)
{
cause.span = impl_item_span;
@@ -256,7 +253,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
tcx.impl_item_implementor_ids(impl_def_id).get(&item_def_id)
&& let Some(impl_item_span) = items
.iter()
- .find(|item| item.id.def_id.to_def_id() == impl_item_id)
+ .find(|item| item.id.owner_id.to_def_id() == impl_item_id)
.map(fix_span)
{
cause.span = impl_item_span;
@@ -275,7 +272,7 @@ impl<'tcx> WfPredicates<'tcx> {
traits::ObligationCause::new(self.span, self.body_id, code)
}
- fn normalize(self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<traits::PredicateObligation<'tcx>> {
+ fn normalize(self, infcx: &InferCtxt<'tcx>) -> Vec<traits::PredicateObligation<'tcx>> {
let cause = self.cause(traits::WellFormed(None));
let param_env = self.param_env;
let mut obligations = Vec::with_capacity(self.out.len());
@@ -392,7 +389,8 @@ impl<'tcx> WfPredicates<'tcx> {
// `i32: Clone`
// `i32: Copy`
// ]
- let obligations = self.nominal_obligations(data.item_def_id, data.substs);
+ // Projection types do not require const predicates.
+ let obligations = self.nominal_obligations_without_const(data.item_def_id, data.substs);
self.out.extend(obligations);
let tcx = self.tcx();
@@ -449,14 +447,14 @@ impl<'tcx> WfPredicates<'tcx> {
// obligations are handled by the parent (e.g. `ty::Ref`).
GenericArgKind::Lifetime(_) => continue,
- GenericArgKind::Const(constant) => {
- match constant.kind() {
+ GenericArgKind::Const(ct) => {
+ match ct.kind() {
ty::ConstKind::Unevaluated(uv) => {
let obligations = self.nominal_obligations(uv.def.did, uv.substs);
self.out.extend(obligations);
let predicate =
- ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv))
+ ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct))
.to_predicate(self.tcx());
let cause = self.cause(traits::WellFormed(None));
self.out.push(traits::Obligation::with_depth(
@@ -473,7 +471,7 @@ impl<'tcx> WfPredicates<'tcx> {
cause,
self.recursion_depth,
self.param_env,
- ty::Binder::dummy(ty::PredicateKind::WellFormed(constant.into()))
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into()))
.to_predicate(self.tcx()),
));
}
@@ -549,7 +547,7 @@ impl<'tcx> WfPredicates<'tcx> {
}
ty::FnDef(did, substs) => {
- let obligations = self.nominal_obligations(did, substs);
+ let obligations = self.nominal_obligations_without_const(did, substs);
self.out.extend(obligations);
}
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index ff5ca0cbc..0de28b826 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -7,8 +7,8 @@
//! `crate::chalk::lowering` (to lower rustc types into Chalk types).
use rustc_middle::traits::ChalkRustInterner as RustInterner;
-use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::{self, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
+use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_ast::ast;
use rustc_attr as attr;
diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs
index a20de08b4..d5a8ca5ea 100644
--- a/compiler/rustc_traits/src/dropck_outlives.rs
+++ b/compiler/rustc_traits/src/dropck_outlives.rs
@@ -4,7 +4,7 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::TraitEngineExt as _;
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt};
use rustc_span::source_map::{Span, DUMMY_SP};
use rustc_trait_selection::traits::query::dropck_outlives::trivial_dropck_outlives;
@@ -27,128 +27,120 @@ fn dropck_outlives<'tcx>(
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>, NoSolution> {
debug!("dropck_outlives(goal={:#?})", canonical_goal);
- tcx.infer_ctxt().enter_with_canonical(
- DUMMY_SP,
- &canonical_goal,
- |ref infcx, goal, canonical_inference_vars| {
- let tcx = infcx.tcx;
- let ParamEnvAnd { param_env, value: for_ty } = goal;
-
- let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] };
-
- // A stack of types left to process. Each round, we pop
- // something from the stack and invoke
- // `dtorck_constraint_for_ty`. This may produce new types that
- // have to be pushed on the stack. This continues until we have explored
- // all the reachable types from the type `for_ty`.
- //
- // Example: Imagine that we have the following code:
- //
- // ```rust
- // struct A {
- // value: B,
- // children: Vec<A>,
- // }
- //
- // struct B {
- // value: u32
- // }
- //
- // fn f() {
- // let a: A = ...;
- // ..
- // } // here, `a` is dropped
- // ```
- //
- // at the point where `a` is dropped, we need to figure out
- // which types inside of `a` contain region data that may be
- // accessed by any destructors in `a`. We begin by pushing `A`
- // onto the stack, as that is the type of `a`. We will then
- // invoke `dtorck_constraint_for_ty` which will expand `A`
- // into the types of its fields `(B, Vec<A>)`. These will get
- // pushed onto the stack. Eventually, expanding `Vec<A>` will
- // lead to us trying to push `A` a second time -- to prevent
- // infinite recursion, we notice that `A` was already pushed
- // once and stop.
- let mut ty_stack = vec![(for_ty, 0)];
-
- // Set used to detect infinite recursion.
- let mut ty_set = FxHashSet::default();
-
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
- let cause = ObligationCause::dummy();
- let mut constraints = DropckConstraint::empty();
- while let Some((ty, depth)) = ty_stack.pop() {
- debug!(
- "{} kinds, {} overflows, {} ty_stack",
- result.kinds.len(),
- result.overflows.len(),
- ty_stack.len()
- );
- dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?;
-
- // "outlives" represent types/regions that may be touched
- // by a destructor.
- result.kinds.append(&mut constraints.outlives);
- result.overflows.append(&mut constraints.overflows);
-
- // If we have even one overflow, we should stop trying to evaluate further --
- // chances are, the subsequent overflows for this evaluation won't provide useful
- // information and will just decrease the speed at which we can emit these errors
- // (since we'll be printing for just that much longer for the often enormous types
- // that result here).
- if !result.overflows.is_empty() {
- break;
- }
+ let (ref infcx, goal, canonical_inference_vars) =
+ tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal);
+ let tcx = infcx.tcx;
+ let ParamEnvAnd { param_env, value: for_ty } = goal;
+
+ let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] };
+
+ // A stack of types left to process. Each round, we pop
+ // something from the stack and invoke
+ // `dtorck_constraint_for_ty`. This may produce new types that
+ // have to be pushed on the stack. This continues until we have explored
+ // all the reachable types from the type `for_ty`.
+ //
+ // Example: Imagine that we have the following code:
+ //
+ // ```rust
+ // struct A {
+ // value: B,
+ // children: Vec<A>,
+ // }
+ //
+ // struct B {
+ // value: u32
+ // }
+ //
+ // fn f() {
+ // let a: A = ...;
+ // ..
+ // } // here, `a` is dropped
+ // ```
+ //
+ // at the point where `a` is dropped, we need to figure out
+ // which types inside of `a` contain region data that may be
+ // accessed by any destructors in `a`. We begin by pushing `A`
+ // onto the stack, as that is the type of `a`. We will then
+ // invoke `dtorck_constraint_for_ty` which will expand `A`
+ // into the types of its fields `(B, Vec<A>)`. These will get
+ // pushed onto the stack. Eventually, expanding `Vec<A>` will
+ // lead to us trying to push `A` a second time -- to prevent
+ // infinite recursion, we notice that `A` was already pushed
+ // once and stop.
+ let mut ty_stack = vec![(for_ty, 0)];
+
+ // Set used to detect infinite recursion.
+ let mut ty_set = FxHashSet::default();
+
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+
+ let cause = ObligationCause::dummy();
+ let mut constraints = DropckConstraint::empty();
+ while let Some((ty, depth)) = ty_stack.pop() {
+ debug!(
+ "{} kinds, {} overflows, {} ty_stack",
+ result.kinds.len(),
+ result.overflows.len(),
+ ty_stack.len()
+ );
+ dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?;
+
+ // "outlives" represent types/regions that may be touched
+ // by a destructor.
+ result.kinds.append(&mut constraints.outlives);
+ result.overflows.append(&mut constraints.overflows);
+
+ // If we have even one overflow, we should stop trying to evaluate further --
+ // chances are, the subsequent overflows for this evaluation won't provide useful
+ // information and will just decrease the speed at which we can emit these errors
+ // (since we'll be printing for just that much longer for the often enormous types
+ // that result here).
+ if !result.overflows.is_empty() {
+ break;
+ }
- // dtorck types are "types that will get dropped but which
- // do not themselves define a destructor", more or less. We have
- // to push them onto the stack to be expanded.
- for ty in constraints.dtorck_types.drain(..) {
- match infcx.at(&cause, param_env).normalize(ty) {
- Ok(Normalized { value: ty, obligations }) => {
- fulfill_cx.register_predicate_obligations(infcx, obligations);
-
- debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
-
- match ty.kind() {
- // All parameters live for the duration of the
- // function.
- ty::Param(..) => {}
-
- // A projection that we couldn't resolve - it
- // might have a destructor.
- ty::Projection(..) | ty::Opaque(..) => {
- result.kinds.push(ty.into());
- }
-
- _ => {
- if ty_set.insert(ty) {
- ty_stack.push((ty, depth + 1));
- }
- }
- }
+ // dtorck types are "types that will get dropped but which
+ // do not themselves define a destructor", more or less. We have
+ // to push them onto the stack to be expanded.
+ for ty in constraints.dtorck_types.drain(..) {
+ match infcx.at(&cause, param_env).normalize(ty) {
+ Ok(Normalized { value: ty, obligations }) => {
+ fulfill_cx.register_predicate_obligations(infcx, obligations);
+
+ debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
+
+ match ty.kind() {
+ // All parameters live for the duration of the
+ // function.
+ ty::Param(..) => {}
+
+ // A projection that we couldn't resolve - it
+ // might have a destructor.
+ ty::Projection(..) | ty::Opaque(..) => {
+ result.kinds.push(ty.into());
}
- // We don't actually expect to fail to normalize.
- // That implies a WF error somewhere else.
- Err(NoSolution) => {
- return Err(NoSolution);
+ _ => {
+ if ty_set.insert(ty) {
+ ty_stack.push((ty, depth + 1));
+ }
}
}
}
+
+ // We don't actually expect to fail to normalize.
+ // That implies a WF error somewhere else.
+ Err(NoSolution) => {
+ return Err(NoSolution);
+ }
}
+ }
+ }
- debug!("dropck_outlives: result = {:#?}", result);
+ debug!("dropck_outlives: result = {:#?}", result);
- infcx.make_canonicalized_query_response(
- canonical_inference_vars,
- result,
- &mut *fulfill_cx,
- )
- },
- )
+ infcx.make_canonicalized_query_response(canonical_inference_vars, result, &mut *fulfill_cx)
}
/// Returns a set of constraints that needs to be satisfied in
diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs
index 49c9ba459..493d5de08 100644
--- a/compiler/rustc_traits/src/evaluate_obligation.rs
+++ b/compiler/rustc_traits/src/evaluate_obligation.rs
@@ -18,17 +18,15 @@ fn evaluate_obligation<'tcx>(
debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal);
// HACK This bubble is required for this tests to pass:
// impl-trait/issue99642.rs
- tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter_with_canonical(
- DUMMY_SP,
- &canonical_goal,
- |ref infcx, goal, _canonical_inference_vars| {
- debug!("evaluate_obligation: goal={:#?}", goal);
- let ParamEnvAnd { param_env, value: predicate } = goal;
+ let (ref infcx, goal, _canonical_inference_vars) = tcx
+ .infer_ctxt()
+ .with_opaque_type_inference(DefiningAnchor::Bubble)
+ .build_with_canonical(DUMMY_SP, &canonical_goal);
+ debug!("evaluate_obligation: goal={:#?}", goal);
+ let ParamEnvAnd { param_env, value: predicate } = goal;
- let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical);
- let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
+ let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical);
+ let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
- selcx.evaluate_root_obligation(&obligation)
- },
- )
+ selcx.evaluate_root_obligation(&obligation)
}
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 691b79f10..7d36b9558 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -35,7 +35,7 @@ fn implied_outlives_bounds<'tcx>(
}
fn compute_implied_outlives_bounds<'tcx>(
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
) -> Fallible<Vec<OutlivesBound<'tcx>>> {
@@ -79,7 +79,7 @@ fn compute_implied_outlives_bounds<'tcx>(
// implied bounds in some cases, mostly when dealing with projections.
fulfill_cx.register_predicate_obligations(
infcx,
- obligations.iter().filter(|o| o.predicate.has_infer_types_or_consts()).cloned(),
+ obligations.iter().filter(|o| o.predicate.has_non_region_infer()).cloned(),
);
// From the full set of obligations, just filter down to the
@@ -156,6 +156,9 @@ fn implied_bounds_from_components<'tcx>(
Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
Component::Projection(p) => Some(OutlivesBound::RegionSubProjection(sub_region, p)),
+ Component::Opaque(def_id, substs) => {
+ Some(OutlivesBound::RegionSubOpaque(sub_region, def_id, substs))
+ }
Component::EscapingProjection(_) =>
// If the projection has escaping regions, don't
// try to infer any implied bounds even for its
diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs
index 2d39e973e..0da28737f 100644
--- a/compiler/rustc_traits/src/lib.rs
+++ b/compiler/rustc_traits/src/lib.rs
@@ -3,7 +3,6 @@
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![recursion_limit = "256"]
#[macro_use]
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 5d394ed22..2da64d73d 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -18,9 +18,6 @@ pub(crate) fn provide(p: &mut Providers) {
try_normalize_after_erasing_regions(tcx, goal)
},
- try_normalize_mir_const_after_erasing_regions: |tcx, goal| {
- try_normalize_after_erasing_regions(tcx, goal)
- },
..*p
};
}
@@ -30,30 +27,29 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq +
goal: ParamEnvAnd<'tcx, T>,
) -> Result<T, NoSolution> {
let ParamEnvAnd { param_env, value } = goal;
- tcx.infer_ctxt().enter(|infcx| {
- let cause = ObligationCause::dummy();
- match infcx.at(&cause, param_env).normalize(value) {
- Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => {
- // We don't care about the `obligations`; they are
- // always only region relations, and we are about to
- // erase those anyway:
- debug_assert_eq!(
- normalized_obligations.iter().find(|p| not_outlives_predicate(p.predicate)),
- None,
- );
+ let infcx = tcx.infer_ctxt().build();
+ let cause = ObligationCause::dummy();
+ match infcx.at(&cause, param_env).normalize(value) {
+ Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => {
+ // We don't care about the `obligations`; they are
+ // always only region relations, and we are about to
+ // erase those anyway:
+ debug_assert_eq!(
+ normalized_obligations.iter().find(|p| not_outlives_predicate(p.predicate)),
+ None,
+ );
- let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
- // It's unclear when `resolve_vars` would have an effect in a
- // fresh `InferCtxt`. If this assert does trigger, it will give
- // 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);
- Ok(erased)
- }
- Err(NoSolution) => Err(NoSolution),
+ let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
+ // It's unclear when `resolve_vars` would have an effect in a
+ // fresh `InferCtxt`. If this assert does trigger, it will give
+ // 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);
+ Ok(erased)
}
- })
+ Err(NoSolution) => Err(NoSolution),
+ }
}
fn not_outlives_predicate<'tcx>(p: ty::Predicate<'tcx>) -> bool {
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index 1bb6506b3..bca7458ed 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -5,10 +5,10 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse};
use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::{ObligationCauseCode, TraitEngineExt as _};
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts};
use rustc_middle::ty::{
self, EarlyBinder, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable, Variance,
};
+use rustc_middle::ty::{GenericArg, UserSelfTy, UserSubsts};
use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Predicate, ToPredicate};
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtBuilderExt;
@@ -51,7 +51,7 @@ fn type_op_ascribe_user_type<'tcx>(
/// 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<'a, 'tcx: 'a>(
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
fulfill_cx: &'a mut dyn TraitEngine<'tcx>,
key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
span: Option<Span>,
@@ -68,7 +68,7 @@ pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>(
}
struct AscribeUserTypeCx<'me, 'tcx> {
- infcx: &'me InferCtxt<'me, 'tcx>,
+ infcx: &'me InferCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
span: Span,
fulfill_cx: &'me mut dyn TraitEngine<'tcx>,
@@ -210,7 +210,7 @@ fn type_op_eq<'tcx>(
}
fn type_op_normalize<'tcx, T>(
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
fulfill_cx: &mut dyn TraitEngine<'tcx>,
key: ParamEnvAnd<'tcx, Normalize<T>>,
) -> Fallible<T>
@@ -285,7 +285,7 @@ fn type_op_prove_predicate<'tcx>(
/// 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_prove_predicate_with_cause<'a, 'tcx: 'a>(
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
fulfill_cx: &'a mut dyn TraitEngine<'tcx>,
key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>,
cause: ObligationCause<'tcx>,
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index 211c813b8..acd4fa63d 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -404,7 +404,7 @@ pub(crate) mod rustc {
.unwrap();
trace!(?discr_layout, "computed discriminant layout");
variant_layout = variant_layout.extend(discr_layout).unwrap().0;
- tree = tree.then(Self::from_disr(discr, tcx, layout_summary.discriminant_size));
+ tree = tree.then(Self::from_discr(discr, tcx, layout_summary.discriminant_size));
}
// Next come fields.
@@ -444,11 +444,21 @@ pub(crate) mod rustc {
Ok(tree)
}
- pub fn from_disr(discr: Discr<'tcx>, tcx: TyCtxt<'tcx>, size: usize) -> Self {
- // FIXME(@jswrenn): I'm certain this is missing needed endian nuance.
- let bytes = discr.val.to_ne_bytes();
- let bytes = &bytes[..size];
- Self::Seq(bytes.into_iter().copied().map(|b| Self::from_bits(b)).collect())
+ pub fn from_discr(discr: Discr<'tcx>, tcx: TyCtxt<'tcx>, size: usize) -> Self {
+ use rustc_target::abi::Endian;
+
+ let bytes: [u8; 16];
+ let bytes = match tcx.data_layout.endian {
+ Endian::Little => {
+ bytes = discr.val.to_le_bytes();
+ &bytes[..size]
+ }
+ Endian::Big => {
+ bytes = discr.val.to_be_bytes();
+ &bytes[bytes.len() - size..]
+ }
+ };
+ Self::Seq(bytes.iter().map(|&b| Self::from_bits(b)).collect())
}
}
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
index 64cd70d36..f7cc94e53 100644
--- a/compiler/rustc_transmute/src/lib.rs
+++ b/compiler/rustc_transmute/src/lib.rs
@@ -80,11 +80,11 @@ mod rustc {
}
pub struct TransmuteTypeEnv<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
}
impl<'cx, 'tcx> TransmuteTypeEnv<'cx, 'tcx> {
- pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> Self {
+ pub fn new(infcx: &'cx InferCtxt<'tcx>) -> Self {
Self { infcx }
}
@@ -115,7 +115,7 @@ mod rustc {
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
c: Const<'tcx>,
- ) -> Self {
+ ) -> Option<Self> {
use rustc_middle::ty::ScalarInt;
use rustc_middle::ty::TypeVisitable;
use rustc_span::symbol::sym;
@@ -123,10 +123,15 @@ mod rustc {
let c = c.eval(tcx, param_env);
if let Some(err) = c.error_reported() {
- return Self { alignment: true, lifetimes: true, safety: true, validity: true };
+ return Some(Self {
+ alignment: true,
+ lifetimes: true,
+ safety: true,
+ validity: true,
+ });
}
- let adt_def = c.ty().ty_adt_def().expect("The given `Const` must be an ADT.");
+ let adt_def = c.ty().ty_adt_def()?;
assert_eq!(
tcx.require_lang_item(LangItem::TransmuteOpts, None),
@@ -148,12 +153,12 @@ mod rustc {
fields[field_idx].unwrap_leaf() == ScalarInt::TRUE
};
- Self {
+ Some(Self {
alignment: get_field(sym::alignment),
lifetimes: get_field(sym::lifetimes),
safety: get_field(sym::safety),
validity: get_field(sym::validity),
- }
+ })
}
}
}
diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml
index 52fbd3ae0..5e4ba4730 100644
--- a/compiler/rustc_ty_utils/Cargo.toml
+++ b/compiler/rustc_ty_utils/Cargo.toml
@@ -4,6 +4,8 @@ version = "0.0.0"
edition = "2021"
[dependencies]
+rand = "0.8.4"
+rand_xoshiro = "0.6.0"
tracing = "0.1"
rustc_middle = { path = "../rustc_middle" }
rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
new file mode 100644
index 000000000..73c7eb699
--- /dev/null
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -0,0 +1,551 @@
+use rustc_hir as hir;
+use rustc_hir::lang_items::LangItem;
+use rustc_middle::ty::layout::{
+ fn_can_unwind, FnAbiError, HasParamEnv, HasTyCtxt, LayoutCx, LayoutOf, TyAndLayout,
+};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::config::OptLevel;
+use rustc_span::def_id::DefId;
+use rustc_target::abi::call::{
+ ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
+};
+use rustc_target::abi::*;
+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 };
+}
+
+// NOTE(eddyb) this is private to avoid using it from outside of
+// `fn_abi_of_instance` - any other uses are either too high-level
+// for `Instance` (e.g. typeck would use `Ty::fn_sig` instead),
+// or should go through `FnAbi` instead, to avoid losing any
+// adjustments `fn_abi_of_instance` might be performing.
+#[tracing::instrument(level = "debug", skip(tcx, param_env))]
+fn fn_sig_for_fn_abi<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ instance: ty::Instance<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+) -> ty::PolyFnSig<'tcx> {
+ let ty = instance.ty(tcx, param_env);
+ match *ty.kind() {
+ ty::FnDef(..) => {
+ // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering
+ // parameters unused if they show up in the signature, but not in the `mir::Body`
+ // (i.e. due to being inside a projection that got normalized, see
+ // `src/test/ui/polymorphization/normalized_sig_types.rs`), and codegen not keeping
+ // track of a polymorphization `ParamEnv` to allow normalizing later.
+ //
+ // We normalize the `fn_sig` again after substituting at a later point.
+ let mut sig = match *ty.kind() {
+ ty::FnDef(def_id, substs) => tcx
+ .bound_fn_sig(def_id)
+ .map_bound(|fn_sig| {
+ tcx.normalize_erasing_regions(tcx.param_env(def_id), fn_sig)
+ })
+ .subst(tcx, substs),
+ _ => unreachable!(),
+ };
+
+ if let ty::InstanceDef::VTableShim(..) = instance.def {
+ // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`.
+ sig = sig.map_bound(|mut sig| {
+ let mut inputs_and_output = sig.inputs_and_output.to_vec();
+ inputs_and_output[0] = tcx.mk_mut_ptr(inputs_and_output[0]);
+ sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output);
+ sig
+ });
+ }
+ sig
+ }
+ ty::Closure(def_id, substs) => {
+ let sig = substs.as_closure().sig();
+
+ let bound_vars = tcx.mk_bound_variable_kinds(
+ sig.bound_vars().iter().chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))),
+ );
+ let br = ty::BoundRegion {
+ var: ty::BoundVar::from_usize(bound_vars.len() - 1),
+ kind: ty::BoundRegionKind::BrEnv,
+ };
+ let env_region = ty::ReLateBound(ty::INNERMOST, br);
+ let env_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap();
+
+ let sig = sig.skip_binder();
+ ty::Binder::bind_with_vars(
+ tcx.mk_fn_sig(
+ iter::once(env_ty).chain(sig.inputs().iter().cloned()),
+ sig.output(),
+ sig.c_variadic,
+ sig.unsafety,
+ sig.abi,
+ ),
+ bound_vars,
+ )
+ }
+ ty::Generator(_, substs, _) => {
+ let sig = substs.as_generator().poly_sig();
+
+ let bound_vars = tcx.mk_bound_variable_kinds(
+ sig.bound_vars().iter().chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))),
+ );
+ let br = ty::BoundRegion {
+ var: ty::BoundVar::from_usize(bound_vars.len() - 1),
+ kind: ty::BoundRegionKind::BrEnv,
+ };
+ let env_region = ty::ReLateBound(ty::INNERMOST, br);
+ let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
+
+ let pin_did = tcx.require_lang_item(LangItem::Pin, None);
+ let pin_adt_ref = tcx.adt_def(pin_did);
+ let pin_substs = tcx.intern_substs(&[env_ty.into()]);
+ let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs);
+
+ let sig = sig.skip_binder();
+ let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
+ let state_adt_ref = tcx.adt_def(state_did);
+ let state_substs = tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]);
+ let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
+ ty::Binder::bind_with_vars(
+ tcx.mk_fn_sig(
+ [env_ty, sig.resume_ty].iter(),
+ &ret_ty,
+ false,
+ hir::Unsafety::Normal,
+ rustc_target::spec::abi::Abi::Rust,
+ ),
+ bound_vars,
+ )
+ }
+ _ => bug!("unexpected type {:?} in Instance::fn_sig", ty),
+ }
+}
+
+#[inline]
+fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
+ use rustc_target::spec::abi::Abi::*;
+ match tcx.sess.target.adjust_abi(abi) {
+ RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
+ RustCold => Conv::RustCold,
+
+ // It's the ABI's job to select this, not ours.
+ System { .. } => bug!("system abi should be selected elsewhere"),
+ EfiApi => bug!("eficall abi should be selected elsewhere"),
+
+ Stdcall { .. } => Conv::X86Stdcall,
+ Fastcall { .. } => Conv::X86Fastcall,
+ Vectorcall { .. } => Conv::X86VectorCall,
+ Thiscall { .. } => Conv::X86ThisCall,
+ C { .. } => Conv::C,
+ Unadjusted => Conv::C,
+ Win64 { .. } => Conv::X86_64Win64,
+ SysV64 { .. } => Conv::X86_64SysV,
+ Aapcs { .. } => Conv::ArmAapcs,
+ CCmseNonSecureCall => Conv::CCmseNonSecureCall,
+ PtxKernel => Conv::PtxKernel,
+ Msp430Interrupt => Conv::Msp430Intr,
+ X86Interrupt => Conv::X86Intr,
+ AmdGpuKernel => Conv::AmdGpuKernel,
+ AvrInterrupt => Conv::AvrInterrupt,
+ AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt,
+ Wasm => Conv::C,
+
+ // These API constants ought to be more specific...
+ Cdecl { .. } => Conv::C,
+ }
+}
+
+fn fn_abi_of_fn_ptr<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ query: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
+) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
+ let (param_env, (sig, extra_args)) = query.into_parts();
+
+ let cx = LayoutCx { tcx, param_env };
+ fn_abi_new_uncached(&cx, sig, extra_args, None, None, false)
+}
+
+fn fn_abi_of_instance<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ query: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
+) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
+ let (param_env, (instance, extra_args)) = query.into_parts();
+
+ let sig = fn_sig_for_fn_abi(tcx, instance, param_env);
+
+ let caller_location = if instance.def.requires_caller_location(tcx) {
+ Some(tcx.caller_location_ty())
+ } else {
+ None
+ };
+
+ fn_abi_new_uncached(
+ &LayoutCx { tcx, param_env },
+ sig,
+ extra_args,
+ caller_location,
+ Some(instance.def_id()),
+ matches!(instance.def, ty::InstanceDef::Virtual(..)),
+ )
+}
+
+// Handle safe Rust thin and fat pointers.
+fn adjust_for_rust_scalar<'tcx>(
+ cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
+ attrs: &mut ArgAttributes,
+ scalar: Scalar,
+ layout: TyAndLayout<'tcx>,
+ offset: Size,
+ is_return: bool,
+) {
+ // Booleans are always a noundef i1 that needs to be zero-extended.
+ if scalar.is_bool() {
+ attrs.ext(ArgExtension::Zext);
+ attrs.set(ArgAttribute::NoUndef);
+ return;
+ }
+
+ // Scalars which have invalid values cannot be undef.
+ if !scalar.is_always_valid(&cx) {
+ attrs.set(ArgAttribute::NoUndef);
+ }
+
+ // Only pointer types handled below.
+ let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return };
+
+ if !valid_range.contains(0) {
+ attrs.set(ArgAttribute::NonNull);
+ }
+
+ if let Some(pointee) = layout.pointee_info_at(&cx, offset) {
+ if let Some(kind) = pointee.safe {
+ attrs.pointee_align = Some(pointee.align);
+
+ // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable
+ // for the entire duration of the function as they can be deallocated
+ // at any time. Same for shared mutable references. If LLVM had a
+ // way to say "dereferenceable on entry" we could use it here.
+ attrs.pointee_size = match kind {
+ PointerKind::UniqueBorrowed
+ | PointerKind::UniqueBorrowedPinned
+ | PointerKind::Frozen => pointee.size,
+ PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO,
+ };
+
+ // `Box`, `&T`, and `&mut T` cannot be undef.
+ // Note that this only applies to the value of the pointer itself;
+ // this attribute doesn't make it UB for the pointed-to data to be undef.
+ attrs.set(ArgAttribute::NoUndef);
+
+ // The aliasing rules for `Box<T>` are still not decided, but currently we emit
+ // `noalias` for it. This can be turned off using an unstable flag.
+ // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326
+ let noalias_for_box = cx.tcx.sess.opts.unstable_opts.box_noalias.unwrap_or(true);
+
+ // `&mut` pointer parameters never alias other parameters,
+ // or mutable global data
+ //
+ // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
+ // and can be marked as both `readonly` and `noalias`, as
+ // LLVM's definition of `noalias` is based solely on memory
+ // dependencies rather than pointer equality
+ //
+ // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute
+ // for UniqueBorrowed arguments, so that the codegen backend can decide whether
+ // or not to actually emit the attribute. It can also be controlled with the
+ // `-Zmutable-noalias` debugging option.
+ let no_alias = match kind {
+ PointerKind::SharedMutable
+ | PointerKind::UniqueBorrowed
+ | PointerKind::UniqueBorrowedPinned => false,
+ PointerKind::UniqueOwned => noalias_for_box,
+ PointerKind::Frozen => !is_return,
+ };
+ if no_alias {
+ attrs.set(ArgAttribute::NoAlias);
+ }
+
+ if kind == PointerKind::Frozen && !is_return {
+ attrs.set(ArgAttribute::ReadOnly);
+ }
+
+ if kind == PointerKind::UniqueBorrowed && !is_return {
+ attrs.set(ArgAttribute::NoAliasMutRef);
+ }
+ }
+ }
+}
+
+// FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
+// arguments of this method, into a separate `struct`.
+#[tracing::instrument(level = "debug", skip(cx, caller_location, fn_def_id, force_thin_self_ptr))]
+fn fn_abi_new_uncached<'tcx>(
+ cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+ sig: ty::PolyFnSig<'tcx>,
+ extra_args: &[Ty<'tcx>],
+ caller_location: Option<Ty<'tcx>>,
+ fn_def_id: Option<DefId>,
+ // FIXME(eddyb) replace this with something typed, like an `enum`.
+ force_thin_self_ptr: bool,
+) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
+ let sig = cx.tcx.normalize_erasing_late_bound_regions(cx.param_env, sig);
+
+ let conv = conv_from_spec_abi(cx.tcx(), sig.abi);
+
+ let mut inputs = sig.inputs();
+ let extra_args = if sig.abi == RustCall {
+ assert!(!sig.c_variadic && extra_args.is_empty());
+
+ if let Some(input) = sig.inputs().last() {
+ if let ty::Tuple(tupled_arguments) = input.kind() {
+ inputs = &sig.inputs()[0..sig.inputs().len() - 1];
+ tupled_arguments
+ } else {
+ bug!(
+ "argument to function with \"rust-call\" ABI \
+ is not a tuple"
+ );
+ }
+ } else {
+ bug!(
+ "argument to function with \"rust-call\" ABI \
+ is not a tuple"
+ );
+ }
+ } else {
+ assert!(sig.c_variadic || extra_args.is_empty());
+ extra_args
+ };
+
+ let target = &cx.tcx.sess.target;
+ let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl" | "uclibc");
+ let win_x64_gnu = target.os == "windows" && target.arch == "x86_64" && target.env == "gnu";
+ let linux_s390x_gnu_like =
+ target.os == "linux" && target.arch == "s390x" && target_env_gnu_like;
+ let linux_sparc64_gnu_like =
+ target.os == "linux" && target.arch == "sparc64" && target_env_gnu_like;
+ let linux_powerpc_gnu_like =
+ target.os == "linux" && target.arch == "powerpc" && target_env_gnu_like;
+ use SpecAbi::*;
+ let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
+
+ 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 layout = cx.layout_of(ty)?;
+ let layout = if force_thin_self_ptr && arg_idx == Some(0) {
+ // Don't pass the vtable, it's not an argument of the virtual fn.
+ // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
+ // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
+ make_thin_self_ptr(cx, layout)
+ } else {
+ layout
+ };
+
+ 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);
+ attrs
+ });
+
+ if arg.layout.is_zst() {
+ // For some forsaken reason, x86_64-pc-windows-gnu
+ // doesn't ignore zero-sized struct arguments.
+ // The same is true for {s390x,sparc64,powerpc}-unknown-linux-{gnu,musl,uclibc}.
+ if is_return
+ || rust_abi
+ || (!win_x64_gnu
+ && !linux_s390x_gnu_like
+ && !linux_sparc64_gnu_like
+ && !linux_powerpc_gnu_like)
+ {
+ arg.mode = PassMode::Ignore;
+ }
+ }
+
+ Ok(arg)
+ };
+
+ let mut fn_abi = FnAbi {
+ ret: arg_of(sig.output(), None)?,
+ args: inputs
+ .iter()
+ .copied()
+ .chain(extra_args.iter().copied())
+ .chain(caller_location)
+ .enumerate()
+ .map(|(i, ty)| arg_of(ty, Some(i)))
+ .collect::<Result<_, _>>()?,
+ c_variadic: sig.c_variadic,
+ fixed_count: inputs.len() as u32,
+ conv,
+ can_unwind: fn_can_unwind(cx.tcx(), fn_def_id, sig.abi),
+ };
+ fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi, fn_def_id)?;
+ debug!("fn_abi_new_uncached = {:?}", fn_abi);
+ Ok(cx.tcx.arena.alloc(fn_abi))
+}
+
+#[tracing::instrument(level = "trace", skip(cx))]
+fn fn_abi_adjust_for_abi<'tcx>(
+ cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+ fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>,
+ abi: SpecAbi,
+ fn_def_id: Option<DefId>,
+) -> Result<(), FnAbiError<'tcx>> {
+ if abi == SpecAbi::Unadjusted {
+ return Ok(());
+ }
+
+ if abi == SpecAbi::Rust
+ || abi == SpecAbi::RustCall
+ || abi == SpecAbi::RustIntrinsic
+ || abi == SpecAbi::PlatformIntrinsic
+ {
+ // Look up the deduced parameter attributes for this function, if we have its def ID and
+ // we're optimizing in non-incremental mode. We'll tag its parameters with those attributes
+ // as appropriate.
+ let deduced_param_attrs = if cx.tcx.sess.opts.optimize != OptLevel::No
+ && cx.tcx.sess.opts.incremental.is_none()
+ {
+ fn_def_id.map(|fn_def_id| cx.tcx.deduced_param_attrs(fn_def_id)).unwrap_or_default()
+ } else {
+ &[]
+ };
+
+ let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, arg_idx: Option<usize>| {
+ if arg.is_ignore() {
+ return;
+ }
+
+ match arg.layout.abi {
+ Abi::Aggregate { .. } => {}
+
+ // This is a fun case! The gist of what this is doing is
+ // that we want callers and callees to always agree on the
+ // ABI of how they pass SIMD arguments. If we were to *not*
+ // make these arguments indirect then they'd be immediates
+ // in LLVM, which means that they'd used whatever the
+ // appropriate ABI is for the callee and the caller. That
+ // means, for example, if the caller doesn't have AVX
+ // enabled but the callee does, then passing an AVX argument
+ // across this boundary would cause corrupt data to show up.
+ //
+ // This problem is fixed by unconditionally passing SIMD
+ // arguments through memory between callers and callees
+ // which should get them all to agree on ABI regardless of
+ // target feature sets. Some more information about this
+ // issue can be found in #44367.
+ //
+ // Note that the platform intrinsic ABI is exempt here as
+ // that's how we connect up to LLVM and it's unstable
+ // anyway, we control all calls to it in libstd.
+ Abi::Vector { .. }
+ if abi != SpecAbi::PlatformIntrinsic
+ && cx.tcx.sess.target.simd_types_indirect =>
+ {
+ arg.make_indirect();
+ return;
+ }
+
+ _ => return,
+ }
+
+ let size = arg.layout.size;
+ if arg.layout.is_unsized() || size > Pointer.size(cx) {
+ arg.make_indirect();
+ } else {
+ // We want to pass small aggregates as immediates, but using
+ // a LLVM aggregate type for this leads to bad optimizations,
+ // so we pick an appropriately sized integer type instead.
+ arg.cast_to(Reg { kind: RegKind::Integer, size });
+ }
+
+ // If we deduced that this parameter was read-only, add that to the attribute list now.
+ //
+ // The `readonly` parameter only applies to pointers, so we can only do this if the
+ // argument was passed indirectly. (If the argument is passed directly, it's an SSA
+ // value, so it's implicitly immutable.)
+ if let (Some(arg_idx), &mut PassMode::Indirect { ref mut attrs, .. }) =
+ (arg_idx, &mut arg.mode)
+ {
+ // The `deduced_param_attrs` list could be empty if this is a type of function
+ // we can't deduce any parameters for, so make sure the argument index is in
+ // bounds.
+ if let Some(deduced_param_attrs) = deduced_param_attrs.get(arg_idx) {
+ if deduced_param_attrs.read_only {
+ attrs.regular.insert(ArgAttribute::ReadOnly);
+ debug!("added deduced read-only attribute");
+ }
+ }
+ }
+ };
+
+ fixup(&mut fn_abi.ret, None);
+ for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() {
+ fixup(arg, Some(arg_idx));
+ }
+ } else {
+ fn_abi.adjust_for_foreign_abi(cx, abi)?;
+ }
+
+ Ok(())
+}
+
+#[tracing::instrument(level = "debug", skip(cx))]
+fn make_thin_self_ptr<'tcx>(
+ cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>),
+ layout: TyAndLayout<'tcx>,
+) -> TyAndLayout<'tcx> {
+ let tcx = cx.tcx();
+ let fat_pointer_ty = if layout.is_unsized() {
+ // unsized `self` is passed as a pointer to `self`
+ // FIXME (mikeyhew) change this to use &own if it is ever added to the language
+ tcx.mk_mut_ptr(layout.ty)
+ } else {
+ match layout.abi {
+ Abi::ScalarPair(..) | Abi::Scalar(..) => (),
+ _ => bug!("receiver type has unsupported layout: {:?}", layout),
+ }
+
+ // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
+ // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
+ // elsewhere in the compiler as a method on a `dyn Trait`.
+ // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
+ // get a built-in pointer type
+ let mut fat_pointer_layout = layout;
+ 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
+ && !fat_pointer_layout.ty.is_region_ptr()
+ {
+ for i in 0..fat_pointer_layout.fields.count() {
+ let field_layout = fat_pointer_layout.field(cx, i);
+
+ if !field_layout.is_zst() {
+ fat_pointer_layout = field_layout;
+ continue 'descend_newtypes;
+ }
+ }
+
+ bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout);
+ }
+
+ fat_pointer_layout.ty
+ };
+
+ // we now have a type like `*mut RcBox<dyn Trait>`
+ // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
+ // this is understood as a special case elsewhere in the compiler
+ let unit_ptr_ty = tcx.mk_mut_ptr(tcx.mk_unit());
+
+ TyAndLayout {
+ ty: fat_pointer_ty,
+
+ // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing the `Result`
+ // should always work because the type is always `*mut ()`.
+ ..tcx.layout_of(ty::ParamEnv::reveal_all().and(unit_ptr_ty)).unwrap()
+ }
+}
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index 515a73ead..424b52309 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -17,10 +17,10 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
let item = tcx.hir().expect_item(def_id.expect_local());
match item.kind {
hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
- trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
+ trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id()),
),
hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
- impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()),
+ impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()),
),
hir::ItemKind::TraitAlias(..) => &[],
_ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
@@ -42,11 +42,11 @@ fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> FxHashMap<DefId
fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
let parent_def_id = tcx.hir().get_parent_item(id);
- let parent_item = tcx.hir().expect_item(parent_def_id);
+ let parent_item = tcx.hir().expect_item(parent_def_id.def_id);
match parent_item.kind {
hir::ItemKind::Impl(ref impl_) => {
if let Some(impl_item_ref) =
- impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
+ impl_.items.iter().find(|i| i.id.owner_id.to_def_id() == def_id)
{
let assoc_item = associated_item_from_impl_item_ref(impl_item_ref);
debug_assert_eq!(assoc_item.def_id, def_id);
@@ -56,7 +56,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
hir::ItemKind::Trait(.., ref trait_item_refs) => {
if let Some(trait_item_ref) =
- trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
+ trait_item_refs.iter().find(|i| i.id.owner_id.to_def_id() == def_id)
{
let assoc_item = associated_item_from_trait_item_ref(trait_item_ref);
debug_assert_eq!(assoc_item.def_id, def_id);
@@ -75,7 +75,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
}
fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem {
- let def_id = trait_item_ref.id.def_id;
+ let owner_id = trait_item_ref.id.owner_id;
let (kind, has_self) = match trait_item_ref.kind {
hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
@@ -85,15 +85,15 @@ fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty
ty::AssocItem {
name: trait_item_ref.ident.name,
kind,
- def_id: def_id.to_def_id(),
- trait_item_def_id: Some(def_id.to_def_id()),
+ def_id: owner_id.to_def_id(),
+ trait_item_def_id: Some(owner_id.to_def_id()),
container: ty::TraitContainer,
fn_has_self_parameter: has_self,
}
}
fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
- let def_id = impl_item_ref.id.def_id;
+ let def_id = impl_item_ref.id.owner_id;
let (kind, has_self) = match impl_item_ref.kind {
hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs
index cedc84d97..d3169b6d9 100644
--- a/compiler/rustc_ty_utils/src/common_traits.rs
+++ b/compiler/rustc_ty_utils/src/common_traits.rs
@@ -29,15 +29,8 @@ fn is_item_raw<'tcx>(
) -> bool {
let (param_env, ty) = query.into_parts();
let trait_def_id = tcx.require_lang_item(item, None);
- tcx.infer_ctxt().enter(|infcx| {
- traits::type_known_to_meet_bound_modulo_regions(
- &infcx,
- param_env,
- ty,
- trait_def_id,
- DUMMY_SP,
- )
- })
+ let infcx = tcx.infer_ctxt().build();
+ traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id, DUMMY_SP)
}
pub(crate) fn provide(providers: &mut ty::query::Providers) {
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 44c4fc48d..e057bb668 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -135,30 +135,30 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
fn expr_is_poly(&mut self, expr: &thir::Expr<'tcx>) -> bool {
- if expr.ty.has_param_types_or_consts() {
+ if expr.ty.has_non_region_param() {
return true;
}
match expr.kind {
- thir::ExprKind::NamedConst { substs, .. } => substs.has_param_types_or_consts(),
+ thir::ExprKind::NamedConst { substs, .. } => substs.has_non_region_param(),
thir::ExprKind::ConstParam { .. } => true,
thir::ExprKind::Repeat { value, count } => {
self.visit_expr(&self.thir()[value]);
- count.has_param_types_or_consts()
+ count.has_non_region_param()
}
_ => false,
}
}
fn pat_is_poly(&mut self, pat: &thir::Pat<'tcx>) -> bool {
- if pat.ty.has_param_types_or_consts() {
+ if pat.ty.has_non_region_param() {
return true;
}
match pat.kind {
- thir::PatKind::Constant { value } => value.has_param_types_or_consts(),
+ thir::PatKind::Constant { value } => value.has_non_region_param(),
thir::PatKind::Range(box thir::PatRange { lo, hi, .. }) => {
- lo.has_param_types_or_consts() || hi.has_param_types_or_consts()
+ lo.has_non_region_param() || hi.has_non_region_param()
}
_ => false,
}
@@ -258,7 +258,8 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty)))
}
&ExprKind::NamedConst { def_id, substs, user_ty: _ } => {
- let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs);
+ let uneval =
+ ty::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
let constant = self
.tcx
diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs
index 3a8ef96c9..c05eeb353 100644
--- a/compiler/rustc_ty_utils/src/errors.rs
+++ b/compiler/rustc_ty_utils/src/errors.rs
@@ -1,69 +1,69 @@
//! Errors emitted by ty_utils
-use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
+use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
use rustc_span::Span;
-#[derive(SessionDiagnostic)]
-#[diag(ty_utils::needs_drop_overflow)]
+#[derive(Diagnostic)]
+#[diag(ty_utils_needs_drop_overflow)]
pub struct NeedsDropOverflow<'tcx> {
pub query_ty: Ty<'tcx>,
}
-#[derive(SessionDiagnostic)]
-#[diag(ty_utils::generic_constant_too_complex)]
+#[derive(Diagnostic)]
+#[diag(ty_utils_generic_constant_too_complex)]
#[help]
pub struct GenericConstantTooComplex {
#[primary_span]
pub span: Span,
- #[note(ty_utils::maybe_supported)]
+ #[note(maybe_supported)]
pub maybe_supported: Option<()>,
#[subdiagnostic]
pub sub: GenericConstantTooComplexSub,
}
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
pub enum GenericConstantTooComplexSub {
- #[label(ty_utils::borrow_not_supported)]
+ #[label(ty_utils_borrow_not_supported)]
BorrowNotSupported(#[primary_span] Span),
- #[label(ty_utils::address_and_deref_not_supported)]
+ #[label(ty_utils_address_and_deref_not_supported)]
AddressAndDerefNotSupported(#[primary_span] Span),
- #[label(ty_utils::array_not_supported)]
+ #[label(ty_utils_array_not_supported)]
ArrayNotSupported(#[primary_span] Span),
- #[label(ty_utils::block_not_supported)]
+ #[label(ty_utils_block_not_supported)]
BlockNotSupported(#[primary_span] Span),
- #[label(ty_utils::never_to_any_not_supported)]
+ #[label(ty_utils_never_to_any_not_supported)]
NeverToAnyNotSupported(#[primary_span] Span),
- #[label(ty_utils::tuple_not_supported)]
+ #[label(ty_utils_tuple_not_supported)]
TupleNotSupported(#[primary_span] Span),
- #[label(ty_utils::index_not_supported)]
+ #[label(ty_utils_index_not_supported)]
IndexNotSupported(#[primary_span] Span),
- #[label(ty_utils::field_not_supported)]
+ #[label(ty_utils_field_not_supported)]
FieldNotSupported(#[primary_span] Span),
- #[label(ty_utils::const_block_not_supported)]
+ #[label(ty_utils_const_block_not_supported)]
ConstBlockNotSupported(#[primary_span] Span),
- #[label(ty_utils::adt_not_supported)]
+ #[label(ty_utils_adt_not_supported)]
AdtNotSupported(#[primary_span] Span),
- #[label(ty_utils::pointer_not_supported)]
+ #[label(ty_utils_pointer_not_supported)]
PointerNotSupported(#[primary_span] Span),
- #[label(ty_utils::yield_not_supported)]
+ #[label(ty_utils_yield_not_supported)]
YieldNotSupported(#[primary_span] Span),
- #[label(ty_utils::loop_not_supported)]
+ #[label(ty_utils_loop_not_supported)]
LoopNotSupported(#[primary_span] Span),
- #[label(ty_utils::box_not_supported)]
+ #[label(ty_utils_box_not_supported)]
BoxNotSupported(#[primary_span] Span),
- #[label(ty_utils::binary_not_supported)]
+ #[label(ty_utils_binary_not_supported)]
BinaryNotSupported(#[primary_span] Span),
- #[label(ty_utils::logical_op_not_supported)]
+ #[label(ty_utils_logical_op_not_supported)]
LogicalOpNotSupported(#[primary_span] Span),
- #[label(ty_utils::assign_not_supported)]
+ #[label(ty_utils_assign_not_supported)]
AssignNotSupported(#[primary_span] Span),
- #[label(ty_utils::closure_and_return_not_supported)]
+ #[label(ty_utils_closure_and_return_not_supported)]
ClosureAndReturnNotSupported(#[primary_span] Span),
- #[label(ty_utils::control_flow_not_supported)]
+ #[label(ty_utils_control_flow_not_supported)]
ControlFlowNotSupported(#[primary_span] Span),
- #[label(ty_utils::inline_asm_not_supported)]
+ #[label(ty_utils_inline_asm_not_supported)]
InlineAsmNotSupported(#[primary_span] Span),
- #[label(ty_utils::operation_not_supported)]
+ #[label(ty_utils_operation_not_supported)]
OperationNotSupported(#[primary_span] Span),
}
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 05738b6c4..6436713b3 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -4,7 +4,7 @@ use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::traits::CodegenObligationError;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitable};
-use rustc_span::{sym, DUMMY_SP};
+use rustc_span::sym;
use rustc_trait_selection::traits;
use traits::{translate_substs, Reveal};
@@ -134,19 +134,17 @@ fn resolve_associated_item<'tcx>(
.unwrap_or_else(|| {
bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id);
});
-
- let substs = tcx.infer_ctxt().enter(|infcx| {
- let param_env = param_env.with_reveal_all_normalized(tcx);
- let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
- let substs = translate_substs(
- &infcx,
- param_env,
- impl_data.impl_def_id,
- substs,
- leaf_def.defining_node,
- );
- infcx.tcx.erase_regions(substs)
- });
+ let infcx = tcx.infer_ctxt().build();
+ let param_env = param_env.with_reveal_all_normalized(tcx);
+ let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
+ let substs = translate_substs(
+ &infcx,
+ param_env,
+ impl_data.impl_def_id,
+ substs,
+ leaf_def.defining_node,
+ );
+ let substs = infcx.tcx.erase_regions(substs);
// Since this is a trait item, we need to see if the item is either a trait default item
// or a specialization because we can't resolve those unless we can `Reveal::All`.
@@ -171,9 +169,13 @@ fn resolve_associated_item<'tcx>(
return Ok(None);
}
- // If the item does not have a value, then we cannot return an instance.
+ // Any final impl is required to define all associated items.
if !leaf_def.item.defaultness(tcx).has_value() {
- return Ok(None);
+ let guard = tcx.sess.delay_span_bug(
+ tcx.def_span(leaf_def.item.def_id),
+ "missing value for assoc item in impl",
+ );
+ return Err(guard);
}
let substs = tcx.erase_regions(substs);
@@ -182,40 +184,14 @@ fn resolve_associated_item<'tcx>(
// a `trait` to an associated `const` definition in an `impl`, where
// the definition in the `impl` has the wrong type (for which an
// error has already been/will be emitted elsewhere).
- //
- // NB: this may be expensive, we try to skip it in all the cases where
- // we know the error would've been caught (e.g. in an upstream crate).
- //
- // A better approach might be to just introduce a query (returning
- // `Result<(), ErrorGuaranteed>`) for the check that `rustc_typeck`
- // performs (i.e. that the definition's type in the `impl` matches
- // the declaration in the `trait`), so that we can cheaply check
- // here if it failed, instead of approximating it.
if leaf_def.item.kind == ty::AssocKind::Const
&& trait_item_id != leaf_def.item.def_id
- && leaf_def.item.def_id.is_local()
+ && let Some(leaf_def_item) = leaf_def.item.def_id.as_local()
{
- let normalized_type_of = |def_id, substs| {
- tcx.subst_and_normalize_erasing_regions(substs, param_env, tcx.type_of(def_id))
- };
-
- let original_ty = normalized_type_of(trait_item_id, rcvr_substs);
- let resolved_ty = normalized_type_of(leaf_def.item.def_id, substs);
-
- if original_ty != resolved_ty {
- let msg = format!(
- "Instance::resolve: inconsistent associated `const` type: \
- was `{}: {}` but resolved to `{}: {}`",
- tcx.def_path_str_with_substs(trait_item_id, rcvr_substs),
- original_ty,
- tcx.def_path_str_with_substs(leaf_def.item.def_id, substs),
- resolved_ty,
- );
- let span = tcx.def_span(leaf_def.item.def_id);
- let reported = tcx.sess.delay_span_bug(span, &msg);
-
- return Err(reported);
- }
+ tcx.compare_assoc_const_impl_item_with_trait_item((
+ leaf_def_item,
+ trait_item_id,
+ ))?;
}
Some(ty::Instance::new(leaf_def.item.def_id, substs))
@@ -260,7 +236,7 @@ fn resolve_associated_item<'tcx>(
if name == sym::clone {
let self_ty = trait_ref.self_ty();
- let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env);
+ let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env);
match self_ty.kind() {
_ if is_copy => (),
ty::Generator(..)
@@ -291,8 +267,7 @@ fn resolve_associated_item<'tcx>(
| traits::ImplSource::DiscriminantKind(..)
| traits::ImplSource::Pointee(..)
| traits::ImplSource::TraitUpcasting(_)
- | traits::ImplSource::ConstDestruct(_)
- | traits::ImplSource::Tuple => None,
+ | traits::ImplSource::ConstDestruct(_) => None,
})
}
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
new file mode 100644
index 000000000..52ba0eee9
--- /dev/null
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -0,0 +1,1803 @@
+use rustc_hir as hir;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::mir::{GeneratorLayout, GeneratorSavedLocal};
+use rustc_middle::ty::layout::{
+ IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
+};
+use rustc_middle::ty::{
+ self, subst::SubstsRef, EarlyBinder, ReprOptions, Ty, TyCtxt, TypeVisitable,
+};
+use rustc_session::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
+use rustc_span::symbol::Symbol;
+use rustc_span::DUMMY_SP;
+use rustc_target::abi::*;
+
+use std::cmp::{self, Ordering};
+use std::iter;
+use std::num::NonZeroUsize;
+use std::ops::Bound;
+
+use rand::{seq::SliceRandom, SeedableRng};
+use rand_xoshiro::Xoshiro128StarStar;
+
+use crate::layout_sanity_check::sanity_check_layout;
+
+pub fn provide(providers: &mut ty::query::Providers) {
+ *providers = ty::query::Providers { layout_of, ..*providers };
+}
+
+#[instrument(skip(tcx, query), level = "debug")]
+fn layout_of<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
+ let (param_env, ty) = query.into_parts();
+ debug!(?ty);
+
+ let param_env = param_env.with_reveal_all_normalized(tcx);
+ let unnormalized_ty = ty;
+
+ // FIXME: We might want to have two different versions of `layout_of`:
+ // One that can be called after typecheck has completed and can use
+ // `normalize_erasing_regions` here and another one that can be called
+ // before typecheck has completed and uses `try_normalize_erasing_regions`.
+ let ty = match tcx.try_normalize_erasing_regions(param_env, ty) {
+ Ok(t) => t,
+ Err(normalization_error) => {
+ return Err(LayoutError::NormalizationFailure(ty, normalization_error));
+ }
+ };
+
+ if ty != unnormalized_ty {
+ // Ensure this layout is also cached for the normalized type.
+ return tcx.layout_of(param_env.and(ty));
+ }
+
+ let cx = LayoutCx { tcx, param_env };
+
+ let layout = layout_of_uncached(&cx, ty)?;
+ let layout = TyAndLayout { ty, layout };
+
+ record_layout_for_printing(&cx, layout);
+
+ sanity_check_layout(&cx, &layout);
+
+ Ok(layout)
+}
+
+#[derive(Copy, Clone, Debug)]
+enum StructKind {
+ /// A tuple, closure, or univariant which cannot be coerced to unsized.
+ AlwaysSized,
+ /// A univariant, the last field of which may be coerced to unsized.
+ MaybeUnsized,
+ /// A univariant, but with a prefix of an arbitrary size & alignment (e.g., enum tag).
+ Prefixed(Size, Align),
+}
+
+// Invert a bijective mapping, i.e. `invert(map)[y] = x` if `map[x] = y`.
+// 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.
+fn invert_mapping(map: &[u32]) -> Vec<u32> {
+ let mut inverse = vec![0; map.len()];
+ for i in 0..map.len() {
+ inverse[map[i] as usize] = i as u32;
+ }
+ inverse
+}
+
+fn scalar_pair<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, a: Scalar, b: Scalar) -> LayoutS<'tcx> {
+ let dl = cx.data_layout();
+ let b_align = b.align(dl);
+ let align = a.align(dl).max(b_align).max(dl.aggregate_align);
+ let b_offset = a.size(dl).align_to(b_align.abi);
+ let size = (b_offset + b.size(dl)).align_to(align.abi);
+
+ // HACK(nox): We iter on `b` and then `a` because `max_by_key`
+ // returns the last maximum.
+ let largest_niche = Niche::from_scalar(dl, b_offset, b)
+ .into_iter()
+ .chain(Niche::from_scalar(dl, Size::ZERO, a))
+ .max_by_key(|niche| niche.available(dl));
+
+ LayoutS {
+ variants: Variants::Single { index: VariantIdx::new(0) },
+ fields: FieldsShape::Arbitrary {
+ offsets: vec![Size::ZERO, b_offset],
+ memory_index: vec![0, 1],
+ },
+ abi: Abi::ScalarPair(a, b),
+ largest_niche,
+ align,
+ size,
+ }
+}
+
+fn univariant_uninterned<'tcx>(
+ cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+ ty: Ty<'tcx>,
+ fields: &[TyAndLayout<'_>],
+ repr: &ReprOptions,
+ kind: StructKind,
+) -> Result<LayoutS<'tcx>, LayoutError<'tcx>> {
+ let dl = cx.data_layout();
+ let pack = repr.pack;
+ if pack.is_some() && repr.align.is_some() {
+ cx.tcx.sess.delay_span_bug(DUMMY_SP, "struct cannot be packed and aligned");
+ return Err(LayoutError::Unknown(ty));
+ }
+
+ let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
+
+ let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).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[..end];
+ let field_align = |f: &TyAndLayout<'_>| {
+ if let Some(pack) = pack { f.align.abi.min(pack) } else { f.align.abi }
+ };
+
+ // 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() {
+ // `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.
+ let f = &fields[x as usize];
+ (!f.is_zst(), cmp::Reverse(field_align(f)))
+ });
+ }
+
+ StructKind::Prefixed(..) => {
+ // Sort in ascending alignment so that the layout stays optimal
+ // regardless of the prefix
+ optimizing.sort_by_key(|&x| field_align(&fields[x as usize]));
+ }
+ }
+
+ // 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 = vec![Size::ZERO; fields.len()];
+ 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 as usize];
+ if !sized {
+ cx.tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ &format!(
+ "univariant: field #{} of `{}` comes after unsized field",
+ offsets.len(),
+ ty
+ ),
+ );
+ }
+
+ if field.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 as usize] = 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).ok_or(LayoutError::SizeOverflow(ty))?;
+ }
+
+ 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 { invert_mapping(&inverse_memory_index) } else { inverse_memory_index };
+
+ 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().enumerate().filter(|&(_, f)| !f.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 = scalar_pair(cx, a, b);
+ let pair_offsets = match pair.fields {
+ FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
+ assert_eq!(memory_index, &[0, 1]);
+ offsets
+ }
+ _ => bug!(),
+ };
+ if offsets[i] == pair_offsets[0]
+ && offsets[j] == pair_offsets[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;
+ }
+
+ Ok(LayoutS {
+ variants: Variants::Single { index: VariantIdx::new(0) },
+ fields: FieldsShape::Arbitrary { offsets, memory_index },
+ abi,
+ largest_niche,
+ align,
+ size,
+ })
+}
+
+fn layout_of_uncached<'tcx>(
+ cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+ ty: Ty<'tcx>,
+) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
+ let tcx = cx.tcx;
+ let param_env = cx.param_env;
+ let dl = cx.data_layout();
+ let scalar_unit = |value: Primitive| {
+ let size = value.size(dl);
+ assert!(size.bits() <= 128);
+ Scalar::Initialized { value, valid_range: WrappingRange::full(size) }
+ };
+ let scalar = |value: Primitive| tcx.intern_layout(LayoutS::scalar(cx, scalar_unit(value)));
+
+ let univariant = |fields: &[TyAndLayout<'_>], repr: &ReprOptions, kind| {
+ Ok(tcx.intern_layout(univariant_uninterned(cx, ty, fields, repr, kind)?))
+ };
+ debug_assert!(!ty.has_non_region_infer());
+
+ Ok(match *ty.kind() {
+ // Basic scalars.
+ ty::Bool => tcx.intern_layout(LayoutS::scalar(
+ cx,
+ Scalar::Initialized {
+ value: Int(I8, false),
+ valid_range: WrappingRange { start: 0, end: 1 },
+ },
+ )),
+ ty::Char => tcx.intern_layout(LayoutS::scalar(
+ cx,
+ Scalar::Initialized {
+ value: Int(I32, false),
+ valid_range: WrappingRange { start: 0, end: 0x10FFFF },
+ },
+ )),
+ ty::Int(ity) => scalar(Int(Integer::from_int_ty(dl, ity), true)),
+ ty::Uint(ity) => scalar(Int(Integer::from_uint_ty(dl, ity), false)),
+ ty::Float(fty) => scalar(match fty {
+ ty::FloatTy::F32 => F32,
+ ty::FloatTy::F64 => F64,
+ }),
+ ty::FnPtr(_) => {
+ let mut ptr = scalar_unit(Pointer);
+ ptr.valid_range_mut().start = 1;
+ tcx.intern_layout(LayoutS::scalar(cx, ptr))
+ }
+
+ // The never type.
+ ty::Never => tcx.intern_layout(LayoutS {
+ variants: Variants::Single { index: VariantIdx::new(0) },
+ fields: FieldsShape::Primitive,
+ abi: Abi::Uninhabited,
+ largest_niche: None,
+ align: dl.i8_align,
+ size: Size::ZERO,
+ }),
+
+ // Potentially-wide pointers.
+ ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
+ let mut data_ptr = scalar_unit(Pointer);
+ if !ty.is_unsafe_ptr() {
+ data_ptr.valid_range_mut().start = 1;
+ }
+
+ let pointee = tcx.normalize_erasing_regions(param_env, pointee);
+ if pointee.is_sized(tcx, param_env) {
+ return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr)));
+ }
+
+ let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
+ let metadata = match unsized_part.kind() {
+ ty::Foreign(..) => {
+ return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr)));
+ }
+ ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
+ ty::Dynamic(..) => {
+ let mut vtable = scalar_unit(Pointer);
+ vtable.valid_range_mut().start = 1;
+ vtable
+ }
+ _ => return Err(LayoutError::Unknown(unsized_part)),
+ };
+
+ // Effectively a (ptr, meta) tuple.
+ tcx.intern_layout(scalar_pair(cx, data_ptr, metadata))
+ }
+
+ ty::Dynamic(_, _, ty::DynStar) => {
+ let mut data = scalar_unit(Int(dl.ptr_sized_integer(), false));
+ data.valid_range_mut().start = 0;
+ let mut vtable = scalar_unit(Pointer);
+ vtable.valid_range_mut().start = 1;
+ tcx.intern_layout(scalar_pair(cx, data, vtable))
+ }
+
+ // Arrays and slices.
+ ty::Array(element, mut count) => {
+ if count.has_projections() {
+ count = tcx.normalize_erasing_regions(param_env, count);
+ if count.has_projections() {
+ return Err(LayoutError::Unknown(ty));
+ }
+ }
+
+ let count = count.try_eval_usize(tcx, param_env).ok_or(LayoutError::Unknown(ty))?;
+ let element = cx.layout_of(element)?;
+ let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow(ty))?;
+
+ let abi = if count != 0 && tcx.conservative_is_privately_uninhabited(param_env.and(ty))
+ {
+ Abi::Uninhabited
+ } else {
+ Abi::Aggregate { sized: true }
+ };
+
+ let largest_niche = if count != 0 { element.largest_niche } else { None };
+
+ tcx.intern_layout(LayoutS {
+ variants: Variants::Single { index: VariantIdx::new(0) },
+ fields: FieldsShape::Array { stride: element.size, count },
+ abi,
+ largest_niche,
+ align: element.align,
+ size,
+ })
+ }
+ ty::Slice(element) => {
+ let element = cx.layout_of(element)?;
+ tcx.intern_layout(LayoutS {
+ variants: Variants::Single { index: VariantIdx::new(0) },
+ fields: FieldsShape::Array { stride: element.size, count: 0 },
+ abi: Abi::Aggregate { sized: false },
+ largest_niche: None,
+ align: element.align,
+ size: Size::ZERO,
+ })
+ }
+ ty::Str => tcx.intern_layout(LayoutS {
+ variants: Variants::Single { index: VariantIdx::new(0) },
+ fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
+ abi: Abi::Aggregate { sized: false },
+ largest_niche: None,
+ align: dl.i8_align,
+ size: Size::ZERO,
+ }),
+
+ // Odd unit types.
+ ty::FnDef(..) => univariant(&[], &ReprOptions::default(), StructKind::AlwaysSized)?,
+ ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => {
+ let mut unit = univariant_uninterned(
+ cx,
+ ty,
+ &[],
+ &ReprOptions::default(),
+ StructKind::AlwaysSized,
+ )?;
+ match unit.abi {
+ Abi::Aggregate { ref mut sized } => *sized = false,
+ _ => bug!(),
+ }
+ tcx.intern_layout(unit)
+ }
+
+ ty::Generator(def_id, substs, _) => generator_layout(cx, ty, def_id, substs)?,
+
+ ty::Closure(_, ref substs) => {
+ let tys = substs.as_closure().upvar_tys();
+ univariant(
+ &tys.map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
+ &ReprOptions::default(),
+ StructKind::AlwaysSized,
+ )?
+ }
+
+ ty::Tuple(tys) => {
+ let kind =
+ if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
+
+ univariant(
+ &tys.iter().map(|k| cx.layout_of(k)).collect::<Result<Vec<_>, _>>()?,
+ &ReprOptions::default(),
+ kind,
+ )?
+ }
+
+ // SIMD vector types.
+ ty::Adt(def, substs) if def.repr().simd() => {
+ if !def.is_struct() {
+ // Should have yielded E0517 by now.
+ tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ "#[repr(simd)] was applied to an ADT that is not a struct",
+ );
+ return Err(LayoutError::Unknown(ty));
+ }
+
+ // Supported SIMD vectors are homogeneous ADTs with at least one field:
+ //
+ // * #[repr(simd)] struct S(T, T, T, T);
+ // * #[repr(simd)] struct S { x: T, y: T, z: T, w: T }
+ // * #[repr(simd)] struct S([T; 4])
+ //
+ // where T is a primitive scalar (integer/float/pointer).
+
+ // SIMD vectors with zero fields are not supported.
+ // (should be caught by typeck)
+ if def.non_enum_variant().fields.is_empty() {
+ tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty));
+ }
+
+ // Type of the first ADT field:
+ let f0_ty = def.non_enum_variant().fields[0].ty(tcx, substs);
+
+ // Heterogeneous SIMD vectors are not supported:
+ // (should be caught by typeck)
+ for fi in &def.non_enum_variant().fields {
+ if fi.ty(tcx, substs) != f0_ty {
+ tcx.sess.fatal(&format!("monomorphising heterogeneous SIMD type `{}`", ty));
+ }
+ }
+
+ // The element type and number of elements of the SIMD vector
+ // are obtained from:
+ //
+ // * the element type and length of the single array field, if
+ // the first field is of array type, or
+ //
+ // * the homogeneous field type and the number of fields.
+ let (e_ty, e_len, is_array) = if let ty::Array(e_ty, _) = f0_ty.kind() {
+ // First ADT field is an array:
+
+ // SIMD vectors with multiple array fields are not supported:
+ // (should be caught by typeck)
+ if def.non_enum_variant().fields.len() != 1 {
+ tcx.sess.fatal(&format!(
+ "monomorphising SIMD type `{}` with more than one array field",
+ ty
+ ));
+ }
+
+ // Extract the number of elements from the layout of the array field:
+ let FieldsShape::Array { count, .. } = cx.layout_of(f0_ty)?.layout.fields() else {
+ return Err(LayoutError::Unknown(ty));
+ };
+
+ (*e_ty, *count, true)
+ } else {
+ // First ADT field is not an array:
+ (f0_ty, def.non_enum_variant().fields.len() as _, false)
+ };
+
+ // SIMD vectors of zero length are not supported.
+ // Additionally, lengths are capped at 2^16 as a fixed maximum backends must
+ // support.
+ //
+ // Can't be caught in typeck if the array length is generic.
+ if e_len == 0 {
+ tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty));
+ } else if e_len > MAX_SIMD_LANES {
+ tcx.sess.fatal(&format!(
+ "monomorphising SIMD type `{}` of length greater than {}",
+ ty, MAX_SIMD_LANES,
+ ));
+ }
+
+ // Compute the ABI of the element type:
+ let e_ly = cx.layout_of(e_ty)?;
+ let Abi::Scalar(e_abi) = e_ly.abi else {
+ // This error isn't caught in typeck, e.g., if
+ // the element type of the vector is generic.
+ tcx.sess.fatal(&format!(
+ "monomorphising SIMD type `{}` with a non-primitive-scalar \
+ (integer/float/pointer) element type `{}`",
+ ty, e_ty
+ ))
+ };
+
+ // Compute the size and alignment of the vector:
+ let size = e_ly.size.checked_mul(e_len, dl).ok_or(LayoutError::SizeOverflow(ty))?;
+ let align = dl.vector_align(size);
+ let size = size.align_to(align.abi);
+
+ // Compute the placement of the vector fields:
+ let fields = if is_array {
+ FieldsShape::Arbitrary { offsets: vec![Size::ZERO], memory_index: vec![0] }
+ } else {
+ FieldsShape::Array { stride: e_ly.size, count: e_len }
+ };
+
+ tcx.intern_layout(LayoutS {
+ variants: Variants::Single { index: VariantIdx::new(0) },
+ fields,
+ abi: Abi::Vector { element: e_abi, count: e_len },
+ largest_niche: e_ly.largest_niche,
+ size,
+ align,
+ })
+ }
+
+ // ADTs.
+ ty::Adt(def, substs) => {
+ // Cache the field layouts.
+ let variants = def
+ .variants()
+ .iter()
+ .map(|v| {
+ v.fields
+ .iter()
+ .map(|field| cx.layout_of(field.ty(tcx, substs)))
+ .collect::<Result<Vec<_>, _>>()
+ })
+ .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
+
+ if def.is_union() {
+ if def.repr().pack.is_some() && def.repr().align.is_some() {
+ cx.tcx.sess.delay_span_bug(
+ tcx.def_span(def.did()),
+ "union cannot be packed and aligned",
+ );
+ return Err(LayoutError::Unknown(ty));
+ }
+
+ let mut align =
+ if def.repr().pack.is_some() { dl.i8_align } else { dl.aggregate_align };
+
+ if let Some(repr_align) = def.repr().align {
+ align = align.max(AbiAndPrefAlign::new(repr_align));
+ }
+
+ let optimize = !def.repr().inhibit_union_abi_opt();
+ let mut size = Size::ZERO;
+ let mut abi = Abi::Aggregate { sized: true };
+ let index = VariantIdx::new(0);
+ for field in &variants[index] {
+ assert!(!field.is_unsized());
+ align = align.max(field.align);
+
+ // If all non-ZST fields have the same ABI, forward this ABI
+ if optimize && !field.is_zst() {
+ // 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 }
+ }
+ 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 };
+ }
+ }
+
+ size = cmp::max(size, field.size);
+ }
+
+ if let Some(pack) = def.repr().pack {
+ align = align.min(AbiAndPrefAlign::new(pack));
+ }
+
+ return Ok(tcx.intern_layout(LayoutS {
+ variants: Variants::Single { index },
+ fields: FieldsShape::Union(
+ NonZeroUsize::new(variants[index].len()).ok_or(LayoutError::Unknown(ty))?,
+ ),
+ abi,
+ largest_niche: None,
+ align,
+ size: size.align_to(align.abi),
+ }));
+ }
+
+ // A variant is absent if it's uninhabited and only has ZST fields.
+ // Present uninhabited variants only require space for their fields,
+ // but *not* an encoding of the discriminant (e.g., a tag value).
+ // See issue #49298 for more details on the need to leave space
+ // for non-ZST uninhabited data (mostly partial initialization).
+ let absent = |fields: &[TyAndLayout<'_>]| {
+ let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited());
+ let is_zst = fields.iter().all(|f| f.is_zst());
+ uninhabited && is_zst
+ };
+ let (present_first, present_second) = {
+ let mut present_variants = variants
+ .iter_enumerated()
+ .filter_map(|(i, v)| if absent(v) { None } else { Some(i) });
+ (present_variants.next(), present_variants.next())
+ };
+ let present_first = match present_first {
+ Some(present_first) => present_first,
+ // Uninhabited because it has no variants, or only absent ones.
+ None if def.is_enum() => {
+ return Ok(tcx.layout_of(param_env.and(tcx.types.never))?.layout);
+ }
+ // If it's a struct, still compute a layout so that we can still compute the
+ // field offsets.
+ None => VariantIdx::new(0),
+ };
+
+ let is_struct = !def.is_enum() ||
+ // Only one variant is present.
+ (present_second.is_none() &&
+ // Representation optimizations are allowed.
+ !def.repr().inhibit_enum_layout_opt());
+ if is_struct {
+ // Struct, or univariant enum equivalent to a struct.
+ // (Typechecking will reject discriminant-sizing attrs.)
+
+ let v = present_first;
+ let kind = if def.is_enum() || variants[v].is_empty() {
+ StructKind::AlwaysSized
+ } else {
+ let param_env = tcx.param_env(def.did());
+ let last_field = def.variant(v).fields.last().unwrap();
+ let always_sized = tcx.type_of(last_field.did).is_sized(tcx, param_env);
+ if !always_sized { StructKind::MaybeUnsized } else { StructKind::AlwaysSized }
+ };
+
+ let mut st = univariant_uninterned(cx, ty, &variants[v], &def.repr(), kind)?;
+ st.variants = Variants::Single { index: v };
+
+ if def.is_unsafe_cell() {
+ let hide_niches = |scalar: &mut _| match scalar {
+ Scalar::Initialized { value, valid_range } => {
+ *valid_range = WrappingRange::full(value.size(dl))
+ }
+ // Already doesn't have any niches
+ Scalar::Union { .. } => {}
+ };
+ match &mut st.abi {
+ Abi::Uninhabited => {}
+ Abi::Scalar(scalar) => hide_niches(scalar),
+ Abi::ScalarPair(a, b) => {
+ hide_niches(a);
+ hide_niches(b);
+ }
+ Abi::Vector { element, count: _ } => hide_niches(element),
+ Abi::Aggregate { sized: _ } => {}
+ }
+ st.largest_niche = None;
+ return Ok(tcx.intern_layout(st));
+ }
+
+ let (start, end) = cx.tcx.layout_scalar_valid_range(def.did());
+ match st.abi {
+ Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => {
+ // the asserts ensure that we are not using the
+ // `#[rustc_layout_scalar_valid_range(n)]`
+ // attribute to widen the range of anything as that would probably
+ // result in UB somewhere
+ // FIXME(eddyb) the asserts are probably not needed,
+ // as larger validity ranges would result in missed
+ // optimizations, *not* wrongly assuming the inner
+ // value is valid. e.g. unions enlarge validity ranges,
+ // because the values may be uninitialized.
+ if let Bound::Included(start) = start {
+ // FIXME(eddyb) this might be incorrect - it doesn't
+ // account for wrap-around (end < start) ranges.
+ let valid_range = scalar.valid_range_mut();
+ assert!(valid_range.start <= start);
+ valid_range.start = start;
+ }
+ if let Bound::Included(end) = end {
+ // FIXME(eddyb) this might be incorrect - it doesn't
+ // account for wrap-around (end < start) ranges.
+ let valid_range = scalar.valid_range_mut();
+ assert!(valid_range.end >= end);
+ valid_range.end = end;
+ }
+
+ // Update `largest_niche` if we have introduced a larger niche.
+ let niche = Niche::from_scalar(dl, Size::ZERO, *scalar);
+ if let Some(niche) = niche {
+ match st.largest_niche {
+ Some(largest_niche) => {
+ // Replace the existing niche even if they're equal,
+ // because this one is at a lower offset.
+ if largest_niche.available(dl) <= niche.available(dl) {
+ st.largest_niche = Some(niche);
+ }
+ }
+ None => st.largest_niche = Some(niche),
+ }
+ }
+ }
+ _ => assert!(
+ start == Bound::Unbounded && end == Bound::Unbounded,
+ "nonscalar layout for layout_scalar_valid_range type {:?}: {:#?}",
+ def,
+ st,
+ ),
+ }
+
+ return Ok(tcx.intern_layout(st));
+ }
+
+ // At this point, we have handled all unions and
+ // structs. (We have also handled univariant enums
+ // that allow representation optimization.)
+ assert!(def.is_enum());
+
+ // Until we've decided whether to use the tagged or
+ // niche filling LayoutS, we don't want to intern the
+ // variant layouts, so we can't store them in the
+ // overall LayoutS. Store the overall LayoutS
+ // and the variant LayoutSs here until then.
+ struct TmpLayout<'tcx> {
+ layout: LayoutS<'tcx>,
+ variants: IndexVec<VariantIdx, LayoutS<'tcx>>,
+ }
+
+ let calculate_niche_filling_layout =
+ || -> Result<Option<TmpLayout<'tcx>>, LayoutError<'tcx>> {
+ // The current code for niche-filling relies on variant indices
+ // instead of actual discriminants, so enums with
+ // explicit discriminants (RFC #2363) would misbehave.
+ if def.repr().inhibit_enum_layout_opt()
+ || def
+ .variants()
+ .iter_enumerated()
+ .any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32()))
+ {
+ return Ok(None);
+ }
+
+ if variants.len() < 2 {
+ return Ok(None);
+ }
+
+ let mut align = dl.aggregate_align;
+ let mut variant_layouts = variants
+ .iter_enumerated()
+ .map(|(j, v)| {
+ let mut st = univariant_uninterned(
+ cx,
+ ty,
+ v,
+ &def.repr(),
+ StructKind::AlwaysSized,
+ )?;
+ st.variants = Variants::Single { index: j };
+
+ align = align.max(st.align);
+
+ Ok(st)
+ })
+ .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
+
+ let largest_variant_index = match variant_layouts
+ .iter_enumerated()
+ .max_by_key(|(_i, layout)| layout.size.bytes())
+ .map(|(i, _layout)| i)
+ {
+ None => return Ok(None),
+ Some(i) => i,
+ };
+
+ let all_indices = VariantIdx::new(0)..=VariantIdx::new(variants.len() - 1);
+ let needs_disc = |index: VariantIdx| {
+ index != largest_variant_index && !absent(&variants[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;
+
+ // Find the field with the largest niche
+ let (field_index, niche, (niche_start, niche_scalar)) = match variants
+ [largest_variant_index]
+ .iter()
+ .enumerate()
+ .filter_map(|(j, field)| Some((j, field.largest_niche?)))
+ .max_by_key(|(_, niche)| niche.available(dl))
+ .and_then(|(j, niche)| Some((j, niche, niche.reserve(cx, count)?)))
+ {
+ None => return Ok(None),
+ Some(x) => x,
+ };
+
+ let niche_offset = niche.offset
+ + variant_layouts[largest_variant_index].fields.offset(field_index);
+ let niche_size = niche.value.size(dl);
+ let size = variant_layouts[largest_variant_index].size.align_to(align.abi);
+
+ let all_variants_fit =
+ variant_layouts.iter_enumerated_mut().all(|(i, layout)| {
+ if i == largest_variant_index {
+ return true;
+ }
+
+ layout.largest_niche = None;
+
+ if layout.size <= niche_offset {
+ // This variant will fit before the niche.
+ return true;
+ }
+
+ // Determine if it'll fit after the niche.
+ let this_align = layout.align.abi;
+ let this_offset = (niche_offset + niche_size).align_to(this_align);
+
+ if this_offset + layout.size > size {
+ return false;
+ }
+
+ // It'll fit, but we need to make some adjustments.
+ match layout.fields {
+ FieldsShape::Arbitrary { ref mut offsets, .. } => {
+ for (j, offset) in offsets.iter_mut().enumerate() {
+ if !variants[i][j].is_zst() {
+ *offset += this_offset;
+ }
+ }
+ }
+ _ => {
+ panic!("Layout of fields should be Arbitrary for variants")
+ }
+ }
+
+ // It can't be a Scalar or ScalarPair because the offset isn't 0.
+ if !layout.abi.is_uninhabited() {
+ layout.abi = Abi::Aggregate { sized: true };
+ }
+ layout.size += this_offset;
+
+ true
+ });
+
+ if !all_variants_fit {
+ return Ok(None);
+ }
+
+ let largest_niche = Niche::from_scalar(dl, niche_offset, niche_scalar);
+
+ let others_zst = variant_layouts
+ .iter_enumerated()
+ .all(|(i, layout)| i == largest_variant_index || layout.size == Size::ZERO);
+ let same_size = size == variant_layouts[largest_variant_index].size;
+ let same_align = align == variant_layouts[largest_variant_index].align;
+
+ let abi = if variant_layouts.iter().all(|v| v.abi.is_uninhabited()) {
+ Abi::Uninhabited
+ } else if same_size && same_align && others_zst {
+ match variant_layouts[largest_variant_index].abi {
+ // When the total alignment and size match, we can use the
+ // same ABI as the scalar variant with the reserved niche.
+ Abi::Scalar(_) => Abi::Scalar(niche_scalar),
+ Abi::ScalarPair(first, second) => {
+ // Only the niche is guaranteed to be initialised,
+ // so use union layouts for the other primitive.
+ if niche_offset == Size::ZERO {
+ Abi::ScalarPair(niche_scalar, second.to_union())
+ } else {
+ Abi::ScalarPair(first.to_union(), niche_scalar)
+ }
+ }
+ _ => Abi::Aggregate { sized: true },
+ }
+ } else {
+ Abi::Aggregate { sized: true }
+ };
+
+ let layout = LayoutS {
+ variants: Variants::Multiple {
+ tag: niche_scalar,
+ tag_encoding: TagEncoding::Niche {
+ untagged_variant: largest_variant_index,
+ niche_variants,
+ niche_start,
+ },
+ tag_field: 0,
+ variants: IndexVec::new(),
+ },
+ fields: FieldsShape::Arbitrary {
+ offsets: vec![niche_offset],
+ memory_index: vec![0],
+ },
+ abi,
+ largest_niche,
+ size,
+ align,
+ };
+
+ Ok(Some(TmpLayout { layout, variants: variant_layouts }))
+ };
+
+ let niche_filling_layout = calculate_niche_filling_layout()?;
+
+ let (mut min, mut max) = (i128::MAX, i128::MIN);
+ let discr_type = def.repr().discr_type();
+ let bits = Integer::from_attr(cx, discr_type).size().bits();
+ for (i, discr) in def.discriminants(tcx) {
+ if variants[i].iter().any(|f| f.abi.is_uninhabited()) {
+ continue;
+ }
+ let mut x = discr.val as i128;
+ if discr_type.is_signed() {
+ // sign extend the raw representation to be an i128
+ x = (x << (128 - bits)) >> (128 - bits);
+ }
+ if x < min {
+ min = x;
+ }
+ if x > max {
+ max = x;
+ }
+ }
+ // We might have no inhabited variants, so pretend there's at least one.
+ if (min, max) == (i128::MAX, i128::MIN) {
+ min = 0;
+ max = 0;
+ }
+ assert!(min <= max, "discriminant range is {}...{}", min, max);
+ let (min_ity, signed) = Integer::repr_discr(tcx, ty, &def.repr(), min, max);
+
+ let mut align = dl.aggregate_align;
+ let mut size = Size::ZERO;
+
+ // We're interested in the smallest alignment, so start large.
+ let mut start_align = Align::from_bytes(256).unwrap();
+ assert_eq!(Integer::for_align(dl, start_align), None);
+
+ // repr(C) on an enum tells us to make a (tag, union) layout,
+ // so we need to grow the prefix alignment to be at least
+ // the alignment of the union. (This value is used both for
+ // determining the alignment of the overall enum, and the
+ // determining the alignment of the payload after the tag.)
+ let mut prefix_align = min_ity.align(dl).abi;
+ if def.repr().c() {
+ for fields in &variants {
+ for field in fields {
+ prefix_align = prefix_align.max(field.align.abi);
+ }
+ }
+ }
+
+ // Create the set of structs that represent each variant.
+ let mut layout_variants = variants
+ .iter_enumerated()
+ .map(|(i, field_layouts)| {
+ let mut st = univariant_uninterned(
+ cx,
+ ty,
+ &field_layouts,
+ &def.repr(),
+ StructKind::Prefixed(min_ity.size(), prefix_align),
+ )?;
+ st.variants = Variants::Single { index: i };
+ // Find the first field we can't move later
+ // to make room for a larger discriminant.
+ for field in st.fields.index_by_increasing_offset().map(|j| field_layouts[j]) {
+ if !field.is_zst() || field.align.abi.bytes() != 1 {
+ start_align = start_align.min(field.align.abi);
+ break;
+ }
+ }
+ size = cmp::max(size, st.size);
+ align = align.max(st.align);
+ Ok(st)
+ })
+ .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
+
+ // Align the maximum variant size to the largest alignment.
+ size = size.align_to(align.abi);
+
+ if size.bytes() >= dl.obj_size_bound() {
+ return Err(LayoutError::SizeOverflow(ty));
+ }
+
+ let typeck_ity = Integer::from_attr(dl, def.repr().discr_type());
+ if typeck_ity < min_ity {
+ // It is a bug if Layout decided on a greater discriminant size than typeck for
+ // some reason at this point (based on values discriminant can take on). Mostly
+ // because this discriminant will be loaded, and then stored into variable of
+ // type calculated by typeck. Consider such case (a bug): typeck decided on
+ // byte-sized discriminant, but layout thinks we need a 16-bit to store all
+ // discriminant values. That would be a bug, because then, in codegen, in order
+ // to store this 16-bit discriminant into 8-bit sized temporary some of the
+ // space necessary to represent would have to be discarded (or layout is wrong
+ // on thinking it needs 16 bits)
+ bug!(
+ "layout decided on a larger discriminant type ({:?}) than typeck ({:?})",
+ min_ity,
+ typeck_ity
+ );
+ // However, it is fine to make discr type however large (as an optimisation)
+ // after this point – we’ll just truncate the value we load in codegen.
+ }
+
+ // Check to see if we should use a different type for the
+ // discriminant. We can safely use a type with the same size
+ // as the alignment of the first field of each variant.
+ // We increase the size of the discriminant to avoid LLVM copying
+ // padding when it doesn't need to. This normally causes unaligned
+ // load/stores and excessive memcpy/memset operations. By using a
+ // bigger integer size, LLVM can be sure about its contents and
+ // won't be so conservative.
+
+ // Use the initial field alignment
+ let mut ity = if def.repr().c() || def.repr().int.is_some() {
+ min_ity
+ } else {
+ Integer::for_align(dl, start_align).unwrap_or(min_ity)
+ };
+
+ // If the alignment is not larger than the chosen discriminant size,
+ // don't use the alignment as the final size.
+ if ity <= min_ity {
+ ity = min_ity;
+ } else {
+ // Patch up the variants' first few fields.
+ let old_ity_size = min_ity.size();
+ let new_ity_size = ity.size();
+ for variant in &mut layout_variants {
+ match variant.fields {
+ FieldsShape::Arbitrary { ref mut offsets, .. } => {
+ for i in offsets {
+ if *i <= old_ity_size {
+ assert_eq!(*i, old_ity_size);
+ *i = new_ity_size;
+ }
+ }
+ // We might be making the struct larger.
+ if variant.size <= old_ity_size {
+ variant.size = new_ity_size;
+ }
+ }
+ _ => bug!(),
+ }
+ }
+ }
+
+ let tag_mask = ity.size().unsigned_int_max();
+ let tag = Scalar::Initialized {
+ value: Int(ity, signed),
+ valid_range: WrappingRange {
+ start: (min as u128 & tag_mask),
+ end: (max as u128 & tag_mask),
+ },
+ };
+ let mut abi = Abi::Aggregate { sized: true };
+
+ if layout_variants.iter().all(|v| v.abi.is_uninhabited()) {
+ abi = Abi::Uninhabited;
+ } else if tag.size(dl) == size {
+ // Make sure we only use scalar layout when the enum is entirely its
+ // own tag (i.e. it has no padding nor any non-ZST variant fields).
+ abi = Abi::Scalar(tag);
+ } else {
+ // Try to use a ScalarPair for all tagged enums.
+ let mut common_prim = None;
+ let mut common_prim_initialized_in_all_variants = true;
+ for (field_layouts, layout_variant) in iter::zip(&variants, &layout_variants) {
+ let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else {
+ bug!();
+ };
+ let mut fields = iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst());
+ let (field, offset) = match (fields.next(), fields.next()) {
+ (None, None) => {
+ common_prim_initialized_in_all_variants = false;
+ continue;
+ }
+ (Some(pair), None) => pair,
+ _ => {
+ common_prim = None;
+ break;
+ }
+ };
+ let prim = match field.abi {
+ Abi::Scalar(scalar) => {
+ common_prim_initialized_in_all_variants &=
+ matches!(scalar, Scalar::Initialized { .. });
+ scalar.primitive()
+ }
+ _ => {
+ common_prim = None;
+ break;
+ }
+ };
+ if let Some(pair) = common_prim {
+ // This is pretty conservative. We could go fancier
+ // by conflating things like i32 and u32, or even
+ // realising that (u8, u8) could just cohabit with
+ // u16 or even u32.
+ if pair != (prim, offset) {
+ common_prim = None;
+ break;
+ }
+ } else {
+ common_prim = Some((prim, offset));
+ }
+ }
+ if let Some((prim, offset)) = common_prim {
+ let prim_scalar = if common_prim_initialized_in_all_variants {
+ scalar_unit(prim)
+ } else {
+ // Common prim might be uninit.
+ Scalar::Union { value: prim }
+ };
+ let pair = scalar_pair(cx, tag, prim_scalar);
+ let pair_offsets = match pair.fields {
+ FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
+ assert_eq!(memory_index, &[0, 1]);
+ offsets
+ }
+ _ => bug!(),
+ };
+ if pair_offsets[0] == Size::ZERO
+ && pair_offsets[1] == *offset
+ && 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 we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the
+ // variants to ensure they are consistent. This is because a downcast is
+ // semantically a NOP, and thus should not affect layout.
+ if matches!(abi, Abi::Scalar(..) | Abi::ScalarPair(..)) {
+ for variant in &mut layout_variants {
+ // We only do this for variants with fields; the others are not accessed anyway.
+ // Also do not overwrite any already existing "clever" ABIs.
+ if variant.fields.count() > 0 && matches!(variant.abi, Abi::Aggregate { .. }) {
+ variant.abi = abi;
+ // Also need to bump up the size and alignment, so that the entire value fits in here.
+ variant.size = cmp::max(variant.size, size);
+ variant.align.abi = cmp::max(variant.align.abi, align.abi);
+ }
+ }
+ }
+
+ let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
+
+ let tagged_layout = LayoutS {
+ variants: Variants::Multiple {
+ tag,
+ tag_encoding: TagEncoding::Direct,
+ tag_field: 0,
+ variants: IndexVec::new(),
+ },
+ fields: FieldsShape::Arbitrary { offsets: vec![Size::ZERO], memory_index: vec![0] },
+ largest_niche,
+ abi,
+ align,
+ size,
+ };
+
+ let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants };
+
+ let mut best_layout = match (tagged_layout, niche_filling_layout) {
+ (tl, Some(nl)) => {
+ // Pick the smaller layout; otherwise,
+ // pick the layout with the larger niche; otherwise,
+ // pick tagged as it has simpler codegen.
+ use Ordering::*;
+ let niche_size = |tmp_l: &TmpLayout<'_>| {
+ tmp_l.layout.largest_niche.map_or(0, |n| n.available(dl))
+ };
+ match (
+ tl.layout.size.cmp(&nl.layout.size),
+ niche_size(&tl).cmp(&niche_size(&nl)),
+ ) {
+ (Greater, _) => nl,
+ (Equal, Less) => nl,
+ _ => tl,
+ }
+ }
+ (tl, None) => tl,
+ };
+
+ // Now we can intern the variant layouts and store them in the enum layout.
+ best_layout.layout.variants = match best_layout.layout.variants {
+ Variants::Multiple { tag, tag_encoding, tag_field, .. } => Variants::Multiple {
+ tag,
+ tag_encoding,
+ tag_field,
+ variants: best_layout
+ .variants
+ .into_iter()
+ .map(|layout| tcx.intern_layout(layout))
+ .collect(),
+ },
+ _ => bug!(),
+ };
+
+ tcx.intern_layout(best_layout.layout)
+ }
+
+ // Types with no meaningful known layout.
+ ty::Projection(_) | ty::Opaque(..) => {
+ // NOTE(eddyb) `layout_of` query should've normalized these away,
+ // if that was possible, so there's no reason to try again here.
+ return Err(LayoutError::Unknown(ty));
+ }
+
+ ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => {
+ bug!("Layout::compute: unexpected type `{}`", ty)
+ }
+
+ ty::Bound(..) | ty::Param(_) | ty::Error(_) => {
+ return Err(LayoutError::Unknown(ty));
+ }
+ })
+}
+
+/// Overlap eligibility and variant assignment for each GeneratorSavedLocal.
+#[derive(Clone, Debug, PartialEq)]
+enum SavedLocalEligibility {
+ Unassigned,
+ Assigned(VariantIdx),
+ // FIXME: Use newtype_index so we aren't wasting bytes
+ Ineligible(Option<u32>),
+}
+
+// When laying out generators, we divide our saved local fields into two
+// categories: overlap-eligible and overlap-ineligible.
+//
+// Those fields which are ineligible for overlap go in a "prefix" at the
+// beginning of the layout, and always have space reserved for them.
+//
+// Overlap-eligible fields are only assigned to one variant, so we lay
+// those fields out for each variant and put them right after the
+// prefix.
+//
+// Finally, in the layout details, we point to the fields from the
+// variants they are assigned to. It is possible for some fields to be
+// included in multiple variants. No field ever "moves around" in the
+// layout; its offset is always the same.
+//
+// Also included in the layout are the upvars and the discriminant.
+// These are included as fields on the "outer" layout; they are not part
+// of any variant.
+
+/// Compute the eligibility and assignment of each local.
+fn generator_saved_local_eligibility<'tcx>(
+ info: &GeneratorLayout<'tcx>,
+) -> (BitSet<GeneratorSavedLocal>, IndexVec<GeneratorSavedLocal, SavedLocalEligibility>) {
+ use SavedLocalEligibility::*;
+
+ let mut assignments: IndexVec<GeneratorSavedLocal, SavedLocalEligibility> =
+ IndexVec::from_elem_n(Unassigned, info.field_tys.len());
+
+ // The saved locals not eligible for overlap. These will get
+ // "promoted" to the prefix of our generator.
+ let mut ineligible_locals = BitSet::new_empty(info.field_tys.len());
+
+ // Figure out which of our saved locals are fields in only
+ // one variant. The rest are deemed ineligible for overlap.
+ for (variant_index, fields) in info.variant_fields.iter_enumerated() {
+ for local in fields {
+ match assignments[*local] {
+ Unassigned => {
+ assignments[*local] = Assigned(variant_index);
+ }
+ Assigned(idx) => {
+ // We've already seen this local at another suspension
+ // point, so it is no longer a candidate.
+ trace!(
+ "removing local {:?} in >1 variant ({:?}, {:?})",
+ local,
+ variant_index,
+ idx
+ );
+ ineligible_locals.insert(*local);
+ assignments[*local] = Ineligible(None);
+ }
+ Ineligible(_) => {}
+ }
+ }
+ }
+
+ // Next, check every pair of eligible locals to see if they
+ // conflict.
+ for local_a in info.storage_conflicts.rows() {
+ let conflicts_a = info.storage_conflicts.count(local_a);
+ if ineligible_locals.contains(local_a) {
+ continue;
+ }
+
+ for local_b in info.storage_conflicts.iter(local_a) {
+ // local_a and local_b are storage live at the same time, therefore they
+ // cannot overlap in the generator layout. The only way to guarantee
+ // this is if they are in the same variant, or one is ineligible
+ // (which means it is stored in every variant).
+ if ineligible_locals.contains(local_b) || assignments[local_a] == assignments[local_b] {
+ continue;
+ }
+
+ // If they conflict, we will choose one to make ineligible.
+ // This is not always optimal; it's just a greedy heuristic that
+ // seems to produce good results most of the time.
+ let conflicts_b = info.storage_conflicts.count(local_b);
+ let (remove, other) =
+ if conflicts_a > conflicts_b { (local_a, local_b) } else { (local_b, local_a) };
+ ineligible_locals.insert(remove);
+ assignments[remove] = Ineligible(None);
+ trace!("removing local {:?} due to conflict with {:?}", remove, other);
+ }
+ }
+
+ // Count the number of variants in use. If only one of them, then it is
+ // impossible to overlap any locals in our layout. In this case it's
+ // always better to make the remaining locals ineligible, so we can
+ // lay them out with the other locals in the prefix and eliminate
+ // unnecessary padding bytes.
+ {
+ let mut used_variants = BitSet::new_empty(info.variant_fields.len());
+ for assignment in &assignments {
+ if let Assigned(idx) = assignment {
+ used_variants.insert(*idx);
+ }
+ }
+ if used_variants.count() < 2 {
+ for assignment in assignments.iter_mut() {
+ *assignment = Ineligible(None);
+ }
+ ineligible_locals.insert_all();
+ }
+ }
+
+ // Write down the order of our locals that will be promoted to the prefix.
+ {
+ for (idx, local) in ineligible_locals.iter().enumerate() {
+ assignments[local] = Ineligible(Some(idx as u32));
+ }
+ }
+ debug!("generator saved local assignments: {:?}", assignments);
+
+ (ineligible_locals, assignments)
+}
+
+/// Compute the full generator layout.
+fn generator_layout<'tcx>(
+ cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+ ty: Ty<'tcx>,
+ def_id: hir::def_id::DefId,
+ substs: SubstsRef<'tcx>,
+) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
+ use SavedLocalEligibility::*;
+ let tcx = cx.tcx;
+ let subst_field = |ty: Ty<'tcx>| EarlyBinder(ty).subst(tcx, substs);
+
+ let Some(info) = tcx.generator_layout(def_id) else {
+ return Err(LayoutError::Unknown(ty));
+ };
+ let (ineligible_locals, assignments) = generator_saved_local_eligibility(&info);
+
+ // Build a prefix layout, including "promoting" all ineligible
+ // locals as part of the prefix. We compute the layout of all of
+ // these fields at once to get optimal packing.
+ let tag_index = substs.as_generator().prefix_tys().count();
+
+ // `info.variant_fields` already accounts for the reserved variants, so no need to add them.
+ let max_discr = (info.variant_fields.len() - 1) as u128;
+ let discr_int = Integer::fit_unsigned(max_discr);
+ let discr_int_ty = discr_int.to_ty(tcx, false);
+ let tag = Scalar::Initialized {
+ value: Primitive::Int(discr_int, false),
+ valid_range: WrappingRange { start: 0, end: max_discr },
+ };
+ let tag_layout = cx.tcx.intern_layout(LayoutS::scalar(cx, tag));
+ let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout };
+
+ let promoted_layouts = ineligible_locals
+ .iter()
+ .map(|local| subst_field(info.field_tys[local]))
+ .map(|ty| tcx.mk_maybe_uninit(ty))
+ .map(|ty| cx.layout_of(ty));
+ let prefix_layouts = substs
+ .as_generator()
+ .prefix_tys()
+ .map(|ty| cx.layout_of(ty))
+ .chain(iter::once(Ok(tag_layout)))
+ .chain(promoted_layouts)
+ .collect::<Result<Vec<_>, _>>()?;
+ let prefix = univariant_uninterned(
+ cx,
+ ty,
+ &prefix_layouts,
+ &ReprOptions::default(),
+ StructKind::AlwaysSized,
+ )?;
+
+ let (prefix_size, prefix_align) = (prefix.size, prefix.align);
+
+ // Split the prefix layout into the "outer" fields (upvars and
+ // discriminant) and the "promoted" fields. Promoted fields will
+ // get included in each variant that requested them in
+ // GeneratorLayout.
+ debug!("prefix = {:#?}", prefix);
+ let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields {
+ FieldsShape::Arbitrary { mut offsets, memory_index } => {
+ let mut inverse_memory_index = invert_mapping(&memory_index);
+
+ // "a" (`0..b_start`) and "b" (`b_start..`) correspond to
+ // "outer" and "promoted" fields respectively.
+ let b_start = (tag_index + 1) as u32;
+ let offsets_b = offsets.split_off(b_start as usize);
+ let offsets_a = offsets;
+
+ // Disentangle the "a" and "b" components of `inverse_memory_index`
+ // by preserving the order but keeping only one disjoint "half" each.
+ // FIXME(eddyb) build a better abstraction for permutations, if possible.
+ let inverse_memory_index_b: Vec<_> =
+ inverse_memory_index.iter().filter_map(|&i| i.checked_sub(b_start)).collect();
+ inverse_memory_index.retain(|&i| i < b_start);
+ let inverse_memory_index_a = inverse_memory_index;
+
+ // Since `inverse_memory_index_{a,b}` each only refer to their
+ // respective fields, they can be safely inverted
+ let memory_index_a = invert_mapping(&inverse_memory_index_a);
+ let memory_index_b = invert_mapping(&inverse_memory_index_b);
+
+ let outer_fields =
+ FieldsShape::Arbitrary { offsets: offsets_a, memory_index: memory_index_a };
+ (outer_fields, offsets_b, memory_index_b)
+ }
+ _ => bug!(),
+ };
+
+ let mut size = prefix.size;
+ let mut align = prefix.align;
+ let variants = info
+ .variant_fields
+ .iter_enumerated()
+ .map(|(index, variant_fields)| {
+ // Only include overlap-eligible fields when we compute our variant layout.
+ let variant_only_tys = variant_fields
+ .iter()
+ .filter(|local| match assignments[**local] {
+ Unassigned => bug!(),
+ Assigned(v) if v == index => true,
+ Assigned(_) => bug!("assignment does not match variant"),
+ Ineligible(_) => false,
+ })
+ .map(|local| subst_field(info.field_tys[*local]));
+
+ let mut variant = univariant_uninterned(
+ cx,
+ ty,
+ &variant_only_tys.map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
+ &ReprOptions::default(),
+ StructKind::Prefixed(prefix_size, prefix_align.abi),
+ )?;
+ variant.variants = Variants::Single { index };
+
+ let FieldsShape::Arbitrary { offsets, memory_index } = variant.fields else {
+ bug!();
+ };
+
+ // Now, stitch the promoted and variant-only fields back together in
+ // the order they are mentioned by our GeneratorLayout.
+ // Because we only use some subset (that can differ between variants)
+ // of the promoted fields, we can't just pick those elements of the
+ // `promoted_memory_index` (as we'd end up with gaps).
+ // So instead, we build an "inverse memory_index", as if all of the
+ // promoted fields were being used, but leave the elements not in the
+ // subset as `INVALID_FIELD_IDX`, which we can filter out later to
+ // obtain a valid (bijective) mapping.
+ const INVALID_FIELD_IDX: u32 = !0;
+ let mut combined_inverse_memory_index =
+ vec![INVALID_FIELD_IDX; promoted_memory_index.len() + memory_index.len()];
+ let mut offsets_and_memory_index = iter::zip(offsets, memory_index);
+ let combined_offsets = variant_fields
+ .iter()
+ .enumerate()
+ .map(|(i, local)| {
+ let (offset, memory_index) = match assignments[*local] {
+ Unassigned => bug!(),
+ Assigned(_) => {
+ let (offset, memory_index) = offsets_and_memory_index.next().unwrap();
+ (offset, promoted_memory_index.len() as u32 + memory_index)
+ }
+ Ineligible(field_idx) => {
+ let field_idx = field_idx.unwrap() as usize;
+ (promoted_offsets[field_idx], promoted_memory_index[field_idx])
+ }
+ };
+ combined_inverse_memory_index[memory_index as usize] = i as u32;
+ offset
+ })
+ .collect();
+
+ // Remove the unused slots and invert the mapping to obtain the
+ // combined `memory_index` (also see previous comment).
+ combined_inverse_memory_index.retain(|&i| i != INVALID_FIELD_IDX);
+ let combined_memory_index = invert_mapping(&combined_inverse_memory_index);
+
+ variant.fields = FieldsShape::Arbitrary {
+ offsets: combined_offsets,
+ memory_index: combined_memory_index,
+ };
+
+ size = size.max(variant.size);
+ align = align.max(variant.align);
+ Ok(tcx.intern_layout(variant))
+ })
+ .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
+
+ size = size.align_to(align.abi);
+
+ let abi = if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi().is_uninhabited()) {
+ Abi::Uninhabited
+ } else {
+ Abi::Aggregate { sized: true }
+ };
+
+ let layout = tcx.intern_layout(LayoutS {
+ variants: Variants::Multiple {
+ tag,
+ tag_encoding: TagEncoding::Direct,
+ tag_field: tag_index,
+ variants,
+ },
+ fields: outer_fields,
+ abi,
+ largest_niche: prefix.largest_niche,
+ size,
+ align,
+ });
+ debug!("generator layout ({:?}): {:#?}", ty, layout);
+ Ok(layout)
+}
+
+/// This is invoked by the `layout_of` query to record the final
+/// layout of each type.
+#[inline(always)]
+fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: TyAndLayout<'tcx>) {
+ // If we are running with `-Zprint-type-sizes`, maybe record layouts
+ // for dumping later.
+ if cx.tcx.sess.opts.unstable_opts.print_type_sizes {
+ record_layout_for_printing_outlined(cx, layout)
+ }
+}
+
+fn record_layout_for_printing_outlined<'tcx>(
+ cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+ layout: TyAndLayout<'tcx>,
+) {
+ // Ignore layouts that are done with non-empty environments or
+ // non-monomorphic layouts, as the user only wants to see the stuff
+ // resulting from the final codegen session.
+ if layout.ty.has_non_region_param() || !cx.param_env.caller_bounds().is_empty() {
+ return;
+ }
+
+ // (delay format until we actually need it)
+ let record = |kind, packed, opt_discr_size, variants| {
+ let type_desc = format!("{:?}", layout.ty);
+ cx.tcx.sess.code_stats.record_type_size(
+ kind,
+ type_desc,
+ layout.align.abi,
+ layout.size,
+ packed,
+ opt_discr_size,
+ variants,
+ );
+ };
+
+ let adt_def = match *layout.ty.kind() {
+ ty::Adt(ref adt_def, _) => {
+ debug!("print-type-size t: `{:?}` process adt", layout.ty);
+ adt_def
+ }
+
+ ty::Closure(..) => {
+ debug!("print-type-size t: `{:?}` record closure", layout.ty);
+ record(DataTypeKind::Closure, false, None, vec![]);
+ return;
+ }
+
+ _ => {
+ debug!("print-type-size t: `{:?}` skip non-nominal", layout.ty);
+ return;
+ }
+ };
+
+ let adt_kind = adt_def.adt_kind();
+ let adt_packed = adt_def.repr().pack.is_some();
+
+ let build_variant_info = |n: Option<Symbol>, flds: &[Symbol], layout: TyAndLayout<'tcx>| {
+ let mut min_size = Size::ZERO;
+ let field_info: Vec<_> = flds
+ .iter()
+ .enumerate()
+ .map(|(i, &name)| {
+ let field_layout = layout.field(cx, i);
+ let offset = layout.fields.offset(i);
+ let field_end = offset + field_layout.size;
+ if min_size < field_end {
+ min_size = field_end;
+ }
+ FieldInfo {
+ name,
+ offset: offset.bytes(),
+ size: field_layout.size.bytes(),
+ align: field_layout.align.abi.bytes(),
+ }
+ })
+ .collect();
+
+ VariantInfo {
+ name: n,
+ kind: if layout.is_unsized() { SizeKind::Min } else { SizeKind::Exact },
+ align: layout.align.abi.bytes(),
+ size: if min_size.bytes() == 0 { layout.size.bytes() } else { min_size.bytes() },
+ fields: field_info,
+ }
+ };
+
+ match layout.variants {
+ Variants::Single { index } => {
+ if !adt_def.variants().is_empty() && layout.fields != FieldsShape::Primitive {
+ debug!("print-type-size `{:#?}` variant {}", layout, adt_def.variant(index).name);
+ let variant_def = &adt_def.variant(index);
+ let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
+ record(
+ adt_kind.into(),
+ adt_packed,
+ None,
+ vec![build_variant_info(Some(variant_def.name), &fields, layout)],
+ );
+ } else {
+ // (This case arises for *empty* enums; so give it
+ // zero variants.)
+ record(adt_kind.into(), adt_packed, None, vec![]);
+ }
+ }
+
+ Variants::Multiple { tag, ref tag_encoding, .. } => {
+ debug!(
+ "print-type-size `{:#?}` adt general variants def {}",
+ layout.ty,
+ adt_def.variants().len()
+ );
+ let variant_infos: Vec<_> = adt_def
+ .variants()
+ .iter_enumerated()
+ .map(|(i, variant_def)| {
+ let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
+ build_variant_info(Some(variant_def.name), &fields, layout.for_variant(cx, i))
+ })
+ .collect();
+ record(
+ adt_kind.into(),
+ adt_packed,
+ match tag_encoding {
+ TagEncoding::Direct => Some(tag.size(cx)),
+ _ => None,
+ },
+ variant_infos,
+ );
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/layout_sanity_check.rs b/compiler/rustc_ty_utils/src/layout_sanity_check.rs
index 87c85dcff..100926ad4 100644
--- a/compiler/rustc_middle/src/ty/layout_sanity_check.rs
+++ b/compiler/rustc_ty_utils/src/layout_sanity_check.rs
@@ -1,4 +1,4 @@
-use crate::ty::{
+use rustc_middle::ty::{
layout::{LayoutCx, TyAndLayout},
TyCtxt,
};
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 8524e57cb..cce5a79dd 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -5,13 +5,11 @@
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(let_chains)]
#![feature(control_flow_enum)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(never_type)]
#![feature(box_patterns)]
#![recursion_limit = "256"]
-#![deny(rustc::untranslatable_diagnostic)]
-#![deny(rustc::diagnostic_outside_of_impl)]
#[macro_use]
extern crate rustc_middle;
@@ -20,22 +18,28 @@ extern crate tracing;
use rustc_middle::ty::query::Providers;
+mod abi;
mod assoc;
mod common_traits;
mod consts;
mod errors;
mod implied_bounds;
pub mod instance;
+mod layout;
+mod layout_sanity_check;
mod needs_drop;
pub mod representability;
mod ty;
pub fn provide(providers: &mut Providers) {
+ abi::provide(providers);
assoc::provide(providers);
common_traits::provide(providers);
consts::provide(providers);
implied_bounds::provide(providers);
+ layout::provide(providers);
needs_drop::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 ab5a3d8ae..024dcd591 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -2,7 +2,6 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop};
use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt};
@@ -110,7 +109,7 @@ where
for component in components {
match *component.kind() {
- _ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (),
+ _ if component.is_copy_modulo_regions(tcx, self.param_env) => (),
ty::Closure(_, substs) => {
queue_type(self, substs.as_closure().tupled_upvars_ty());
@@ -265,7 +264,7 @@ fn adt_consider_insignificant_dtor<'tcx>(
if is_marked_insig {
// In some cases like `std::collections::HashMap` where the struct is a wrapper around
// a type that is a Drop type, and the wrapped type (eg: `hashbrown::HashMap`) lies
- // outside stdlib, we might choose to still annotate the the wrapper (std HashMap) with
+ // outside stdlib, we might choose to still annotate the wrapper (std HashMap) with
// `rustc_insignificant_dtor`, even if the type itself doesn't have a `Drop` impl.
Some(DtorType::Insignificant)
} else if adt_def.destructor(tcx).is_some() {
diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs
index eded78916..7f48fb804 100644
--- a/compiler/rustc_ty_utils/src/representability.rs
+++ b/compiler/rustc_ty_utils/src/representability.rs
@@ -1,386 +1,119 @@
-//! Check whether a type is representable.
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir as hir;
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::Span;
-use std::cmp;
+#![allow(rustc::untranslatable_diagnostic, rustc::diagnostic_outside_of_impl)]
-/// Describes whether a type is representable. For types that are not
-/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to
-/// distinguish between types that are recursive with themselves and types that
-/// contain a different recursive type. These cases can therefore be treated
-/// differently when reporting errors.
-///
-/// The ordering of the cases is significant. They are sorted so that cmp::max
-/// will keep the "more erroneous" of two values.
-#[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
-pub enum Representability {
- Representable,
- ContainsRecursive,
- /// Return a list of types that are included in themselves:
- /// the spans where they are self-included, and (if found)
- /// the HirId of the FieldDef that defines the self-inclusion.
- SelfRecursive(Vec<(Span, Option<hir::HirId>)>),
-}
+use rustc_hir::def::DefKind;
+use rustc_index::bit_set::BitSet;
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::{self, Representability, Ty, TyCtxt};
+use rustc_span::def_id::{DefId, LocalDefId};
-/// Check whether a type is representable. This means it cannot contain unboxed
-/// structural recursion. This check is needed for structs and enums.
-pub fn ty_is_representable<'tcx>(
- tcx: TyCtxt<'tcx>,
- ty: Ty<'tcx>,
- sp: Span,
- field_id: Option<hir::HirId>,
-) -> Representability {
- debug!("is_type_representable: {:?}", ty);
- // To avoid a stack overflow when checking an enum variant or struct that
- // contains a different, structurally recursive type, maintain a stack of
- // seen types and check recursion for each of them (issues #3008, #3779,
- // #74224, #84611). `shadow_seen` contains the full stack and `seen` only
- // the one for the current type (e.g. if we have structs A and B, B contains
- // a field of type A, and we're currently looking at B, then `seen` will be
- // cleared when recursing to check A, but `shadow_seen` won't, so that we
- // can catch cases of mutual recursion where A also contains B).
- let mut seen: Vec<Ty<'_>> = Vec::new();
- let mut shadow_seen: Vec<ty::AdtDef<'tcx>> = Vec::new();
- let mut representable_cache = FxHashMap::default();
- let mut force_result = false;
- let r = is_type_structurally_recursive(
- tcx,
- &mut seen,
- &mut shadow_seen,
- &mut representable_cache,
- ty,
- sp,
- field_id,
- &mut force_result,
- );
- debug!("is_type_representable: {:?} is {:?}", ty, r);
- r
+pub fn provide(providers: &mut Providers) {
+ *providers =
+ Providers { representability, representability_adt_ty, params_in_repr, ..*providers };
}
-// Iterate until something non-representable is found
-fn fold_repr<It: Iterator<Item = Representability>>(iter: It) -> Representability {
- iter.fold(Representability::Representable, |r1, r2| match (r1, r2) {
- (Representability::SelfRecursive(v1), Representability::SelfRecursive(v2)) => {
- Representability::SelfRecursive(v1.into_iter().chain(v2).collect())
+macro_rules! rtry {
+ ($e:expr) => {
+ match $e {
+ e @ Representability::Infinite => return e,
+ Representability::Representable => {}
}
- (r1, r2) => cmp::max(r1, r2),
- })
+ };
}
-fn are_inner_types_recursive<'tcx>(
- tcx: TyCtxt<'tcx>,
- seen: &mut Vec<Ty<'tcx>>,
- shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
- representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
- ty: Ty<'tcx>,
- sp: Span,
- field_id: Option<hir::HirId>,
- force_result: &mut bool,
-) -> Representability {
- debug!("are_inner_types_recursive({:?}, {:?}, {:?})", ty, seen, shadow_seen);
- match ty.kind() {
- ty::Tuple(fields) => {
- // Find non representable
- fold_repr(fields.iter().map(|ty| {
- is_type_structurally_recursive(
- tcx,
- seen,
- shadow_seen,
- representable_cache,
- ty,
- sp,
- field_id,
- force_result,
- )
- }))
- }
- // Fixed-length vectors.
- // FIXME(#11924) Behavior undecided for zero-length vectors.
- ty::Array(ty, _) => is_type_structurally_recursive(
- tcx,
- seen,
- shadow_seen,
- representable_cache,
- *ty,
- sp,
- field_id,
- force_result,
- ),
- ty::Adt(def, substs) => {
- // Find non representable fields with their spans
- fold_repr(def.all_fields().map(|field| {
- let ty = field.ty(tcx, substs);
- let (sp, field_id) = match field
- .did
- .as_local()
- .map(|id| tcx.hir().local_def_id_to_hir_id(id))
- .and_then(|id| tcx.hir().find(id))
- {
- Some(hir::Node::Field(field)) => (field.ty.span, Some(field.hir_id)),
- _ => (sp, field_id),
- };
-
- let mut result = None;
-
- // First, we check whether the field type per se is representable.
- // This catches cases as in #74224 and #84611. There is a special
- // case related to mutual recursion, though; consider this example:
- //
- // struct A<T> {
- // z: T,
- // x: B<T>,
- // }
- //
- // struct B<T> {
- // y: A<T>
- // }
- //
- // Here, without the following special case, both A and B are
- // ContainsRecursive, which is a problem because we only report
- // errors for SelfRecursive. We fix this by detecting this special
- // case (shadow_seen.first() is the type we are originally
- // interested in, and if we ever encounter the same AdtDef again,
- // we know that it must be SelfRecursive) and "forcibly" returning
- // SelfRecursive (by setting force_result, which tells the calling
- // invocations of are_inner_types_representable to forward the
- // result without adjusting).
- if shadow_seen.len() > seen.len() && shadow_seen.first() == Some(def) {
- *force_result = true;
- result = Some(Representability::SelfRecursive(vec![(sp, field_id)]));
- }
-
- if result == None {
- result = Some(Representability::Representable);
-
- // Now, we check whether the field types per se are representable, e.g.
- // for struct Foo { x: Option<Foo> }, we first check whether Option<_>
- // by itself is representable (which it is), and the nesting of Foo
- // will be detected later. This is necessary for #74224 and #84611.
-
- // If we have encountered an ADT definition that we have not seen
- // before (no need to check them twice), recurse to see whether that
- // definition is SelfRecursive. If so, we must be ContainsRecursive.
- if shadow_seen.len() > 1
- && !shadow_seen
- .iter()
- .take(shadow_seen.len() - 1)
- .any(|seen_def| seen_def == def)
- {
- let adt_def_id = def.did();
- let raw_adt_ty = tcx.type_of(adt_def_id);
- debug!("are_inner_types_recursive: checking nested type: {:?}", raw_adt_ty);
-
- // Check independently whether the ADT is SelfRecursive. If so,
- // we must be ContainsRecursive (except for the special case
- // mentioned above).
- let mut nested_seen: Vec<Ty<'_>> = vec![];
- result = Some(
- match is_type_structurally_recursive(
- tcx,
- &mut nested_seen,
- shadow_seen,
- representable_cache,
- raw_adt_ty,
- sp,
- field_id,
- force_result,
- ) {
- Representability::SelfRecursive(_) => {
- if *force_result {
- Representability::SelfRecursive(vec![(sp, field_id)])
- } else {
- Representability::ContainsRecursive
- }
- }
- x => x,
- },
- );
- }
-
- // We only enter the following block if the type looks representable
- // so far. This is necessary for cases such as this one (#74224):
- //
- // struct A<T> {
- // x: T,
- // y: A<A<T>>,
- // }
- //
- // struct B {
- // z: A<usize>
- // }
- //
- // When checking B, we recurse into A and check field y of type
- // A<A<usize>>. We haven't seen this exact type before, so we recurse
- // into A<A<usize>>, which contains, A<A<A<usize>>>, and so forth,
- // ad infinitum. We can prevent this from happening by first checking
- // A separately (the code above) and only checking for nested Bs if
- // A actually looks representable (which it wouldn't in this example).
- if result == Some(Representability::Representable) {
- // Now, even if the type is representable (e.g. Option<_>),
- // it might still contribute to a recursive type, e.g.:
- // struct Foo { x: Option<Option<Foo>> }
- // These cases are handled by passing the full `seen`
- // stack to is_type_structurally_recursive (instead of the
- // empty `nested_seen` above):
- result = Some(
- match is_type_structurally_recursive(
- tcx,
- seen,
- shadow_seen,
- representable_cache,
- ty,
- sp,
- field_id,
- force_result,
- ) {
- Representability::SelfRecursive(_) => {
- Representability::SelfRecursive(vec![(sp, field_id)])
- }
- x => x,
- },
- );
- }
+fn representability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Representability {
+ match tcx.def_kind(def_id) {
+ DefKind::Struct | DefKind::Union | DefKind::Enum => {
+ let adt_def = tcx.adt_def(def_id);
+ for variant in adt_def.variants() {
+ for field in variant.fields.iter() {
+ rtry!(tcx.representability(field.did.expect_local()));
}
-
- result.unwrap()
- }))
- }
- ty::Closure(..) => {
- // this check is run on type definitions, so we don't expect
- // to see closure types
- bug!("requires check invoked on inapplicable type: {:?}", ty)
+ }
+ Representability::Representable
}
- _ => Representability::Representable,
+ DefKind::Field => representability_ty(tcx, tcx.type_of(def_id)),
+ def_kind => bug!("unexpected {def_kind:?}"),
}
}
-fn same_adt<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool {
+fn representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representability {
match *ty.kind() {
- ty::Adt(ty_def, _) => ty_def == def,
- _ => false,
+ ty::Adt(..) => tcx.representability_adt_ty(ty),
+ // FIXME(#11924) allow zero-length arrays?
+ ty::Array(ty, _) => representability_ty(tcx, ty),
+ ty::Tuple(tys) => {
+ for ty in tys {
+ rtry!(representability_ty(tcx, ty));
+ }
+ Representability::Representable
+ }
+ _ => Representability::Representable,
}
}
-// Does the type `ty` directly (without indirection through a pointer)
-// contain any types on stack `seen`?
-fn is_type_structurally_recursive<'tcx>(
- tcx: TyCtxt<'tcx>,
- seen: &mut Vec<Ty<'tcx>>,
- shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
- representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
- ty: Ty<'tcx>,
- sp: Span,
- field_id: Option<hir::HirId>,
- force_result: &mut bool,
-) -> Representability {
- debug!("is_type_structurally_recursive: {:?} {:?} {:?}", ty, sp, field_id);
- if let Some(representability) = representable_cache.get(&ty) {
- debug!(
- "is_type_structurally_recursive: {:?} {:?} {:?} - (cached) {:?}",
- ty, sp, field_id, representability
- );
- return representability.clone();
+/*
+The reason for this being a separate query is very subtle:
+Consider this infinitely sized struct: `struct Foo(Box<Foo>, Bar<Foo>)`:
+When calling representability(Foo), a query cycle will occur:
+ representability(Foo)
+ -> representability_adt_ty(Bar<Foo>)
+ -> representability(Foo)
+For the diagnostic output (in `Value::from_cycle_error`), we want to detect that
+the `Foo` in the *second* field of the struct is culpable. This requires
+traversing the HIR of the struct and calling `params_in_repr(Bar)`. But we can't
+call params_in_repr for a given type unless it is known to be representable.
+params_in_repr will cycle/panic on infinitely sized types. Looking at the query
+cycle above, we know that `Bar` is representable because
+representability_adt_ty(Bar<..>) is in the cycle and representability(Bar) is
+*not* in the cycle.
+*/
+fn representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representability {
+ let ty::Adt(adt, substs) = ty.kind() else { bug!("expected adt") };
+ if let Some(def_id) = adt.did().as_local() {
+ rtry!(tcx.representability(def_id));
}
-
- let representability = is_type_structurally_recursive_inner(
- tcx,
- seen,
- shadow_seen,
- representable_cache,
- ty,
- sp,
- field_id,
- force_result,
- );
-
- representable_cache.insert(ty, representability.clone());
- representability
+ // At this point, we know that the item of the ADT type is representable;
+ // but the type parameters may cause a cycle with an upstream type
+ let params_in_repr = tcx.params_in_repr(adt.did());
+ for (i, subst) in substs.iter().enumerate() {
+ if let ty::GenericArgKind::Type(ty) = subst.unpack() {
+ if params_in_repr.contains(i as u32) {
+ rtry!(representability_ty(tcx, ty));
+ }
+ }
+ }
+ Representability::Representable
}
-fn is_type_structurally_recursive_inner<'tcx>(
- tcx: TyCtxt<'tcx>,
- seen: &mut Vec<Ty<'tcx>>,
- shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
- representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
- ty: Ty<'tcx>,
- sp: Span,
- field_id: Option<hir::HirId>,
- force_result: &mut bool,
-) -> Representability {
- match ty.kind() {
- ty::Adt(def, _) => {
- {
- debug!("is_type_structurally_recursive_inner: adt: {:?}, seen: {:?}", ty, seen);
-
- // Iterate through stack of previously seen types.
- let mut iter = seen.iter();
-
- // The first item in `seen` is the type we are actually curious about.
- // We want to return SelfRecursive if this type contains itself.
- // It is important that we DON'T take generic parameters into account
- // for this check, so that Bar<T> in this example counts as SelfRecursive:
- //
- // struct Foo;
- // struct Bar<T> { x: Bar<Foo> }
-
- if let Some(&seen_adt) = iter.next() {
- if same_adt(seen_adt, *def) {
- debug!("SelfRecursive: {:?} contains {:?}", seen_adt, ty);
- return Representability::SelfRecursive(vec![(sp, field_id)]);
- }
- }
-
- // We also need to know whether the first item contains other types
- // that are structurally recursive. If we don't catch this case, we
- // will recurse infinitely for some inputs.
- //
- // It is important that we DO take generic parameters into account
- // here, because nesting e.g. Options is allowed (as long as the
- // definition of Option doesn't itself include an Option field, which
- // would be a case of SelfRecursive above). The following, too, counts
- // as SelfRecursive:
- //
- // struct Foo { Option<Option<Foo>> }
+fn params_in_repr(tcx: TyCtxt<'_>, def_id: DefId) -> BitSet<u32> {
+ let adt_def = tcx.adt_def(def_id);
+ let generics = tcx.generics_of(def_id);
+ let mut params_in_repr = BitSet::new_empty(generics.params.len());
+ for variant in adt_def.variants() {
+ for field in variant.fields.iter() {
+ params_in_repr_ty(tcx, tcx.type_of(field.did), &mut params_in_repr);
+ }
+ }
+ params_in_repr
+}
- for &seen_adt in iter {
- if ty == seen_adt {
- debug!("ContainsRecursive: {:?} contains {:?}", seen_adt, ty);
- return Representability::ContainsRecursive;
+fn params_in_repr_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, params_in_repr: &mut BitSet<u32>) {
+ match *ty.kind() {
+ ty::Adt(adt, substs) => {
+ let inner_params_in_repr = tcx.params_in_repr(adt.did());
+ for (i, subst) in substs.iter().enumerate() {
+ if let ty::GenericArgKind::Type(ty) = subst.unpack() {
+ if inner_params_in_repr.contains(i as u32) {
+ params_in_repr_ty(tcx, ty, params_in_repr);
}
}
}
-
- // For structs and enums, track all previously seen types by pushing them
- // onto the 'seen' stack.
- seen.push(ty);
- shadow_seen.push(*def);
- let out = are_inner_types_recursive(
- tcx,
- seen,
- shadow_seen,
- representable_cache,
- ty,
- sp,
- field_id,
- force_result,
- );
- shadow_seen.pop();
- seen.pop();
- out
}
- _ => {
- // No need to push in other cases.
- are_inner_types_recursive(
- tcx,
- seen,
- shadow_seen,
- representable_cache,
- ty,
- sp,
- field_id,
- force_result,
- )
+ ty::Array(ty, _) => params_in_repr_ty(tcx, ty, params_in_repr),
+ ty::Tuple(tys) => tys.iter().for_each(|ty| params_in_repr_ty(tcx, ty, params_in_repr)),
+ ty::Param(param) => {
+ params_in_repr.insert(param.index);
}
+ _ => {}
}
}
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 9266e4e3f..3eebb4ace 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -1,7 +1,6 @@
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
use rustc_trait_selection::traits;
@@ -86,9 +85,13 @@ fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
/// - a type parameter or projection whose Sizedness can't be known
/// - a tuple of type parameters or projections, if there are multiple
/// such.
-/// - an Error, if a type contained itself. The representability
-/// check should catch this case.
-fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstraint<'_> {
+/// - an Error, if a type is infinitely sized
+fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] {
+ if let Some(def_id) = def_id.as_local() {
+ if matches!(tcx.representability(def_id), ty::Representability::Infinite) {
+ return tcx.intern_type_list(&[tcx.ty_error()]);
+ }
+ }
let def = tcx.adt_def(def_id);
let result = tcx.mk_type_list(
@@ -100,7 +103,7 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstrain
debug!("adt_sized_constraint: {:?} => {:?}", def, result);
- ty::AdtSizedConstraint(result)
+ result
}
/// See `ParamEnv` struct definition for details.
@@ -134,6 +137,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
let local_did = def_id.as_local();
let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
+ // FIXME(consts): This is not exactly in line with the constness query.
let constness = match hir_id {
Some(hir_id) => match tcx.hir().get(hir_id) {
hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
@@ -162,7 +166,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
}) => hir::Constness::Const,
hir::Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::TyAlias(..) | hir::ImplItemKind::Fn(..),
+ kind: hir::ImplItemKind::Type(..) | hir::ImplItemKind::Fn(..),
..
}) => {
let parent_hir_id = tcx.hir().get_parent_node(hir_id);
@@ -198,6 +202,10 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
_ => hir::Constness::NotConst,
},
+ // FIXME(consts): It's suspicious that a param-env for a foreign item
+ // will always have NotConst param-env, though we don't typically use
+ // that param-env for anything meaningful right now, so it's likely
+ // not an issue.
None => hir::Constness::NotConst,
};
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index 5aa3cf017..c4008e9b6 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
bitflags = "1.2.1"
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index da30344ef..7fbe78aa5 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -675,9 +675,9 @@ impl<CTX> HashStable<CTX> for InferTy {
use InferTy::*;
discriminant(self).hash_stable(ctx, hasher);
match self {
- TyVar(v) => v.as_u32().hash_stable(ctx, hasher),
- IntVar(v) => v.index.hash_stable(ctx, hasher),
- FloatVar(v) => v.index.hash_stable(ctx, hasher),
+ TyVar(_) | IntVar(_) | FloatVar(_) => {
+ panic!("type variables should not be hashed: {self:?}")
+ }
FreshTy(v) | FreshIntTy(v) | FreshFloatTy(v) => v.hash_stable(ctx, hasher),
}
}
diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs
index 6d54924e5..a4fb1480f 100644
--- a/compiler/rustc_type_ir/src/sty.rs
+++ b/compiler/rustc_type_ir/src/sty.rs
@@ -1332,8 +1332,8 @@ where
RePlaceholder(p) => {
p.hash_stable(hcx, hasher);
}
- ReVar(reg) => {
- reg.hash_stable(hcx, hasher);
+ ReVar(_) => {
+ panic!("region variables should not be hashed: {self:?}")
}
}
}
diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs
deleted file mode 100644
index d08c0d4db..000000000
--- a/compiler/rustc_typeck/src/coherence/builtin.rs
+++ /dev/null
@@ -1,594 +0,0 @@
-//! 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 rustc_errors::{struct_span_err, MultiSpan};
-use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::lang_items::LangItem;
-use rustc_hir::ItemKind;
-use rustc_infer::infer;
-use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::TyCtxtInferExt;
-use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
-use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitable};
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
-use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
-use rustc_trait_selection::traits::predicate_for_trait_def;
-use rustc_trait_selection::traits::{self, ObligationCause};
-use std::collections::BTreeMap;
-
-pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
- let lang_items = tcx.lang_items();
- 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.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)
- .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn);
-}
-
-struct Checker<'tcx> {
- tcx: TyCtxt<'tcx>,
- trait_def_id: DefId,
-}
-
-impl<'tcx> Checker<'tcx> {
- fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self
- where
- F: FnMut(TyCtxt<'tcx>, LocalDefId),
- {
- if Some(self.trait_def_id) == trait_def_id {
- for &impl_def_id in self.tcx.hir().trait_impls(self.trait_def_id) {
- f(self.tcx, impl_def_id);
- }
- }
- self
- }
-}
-
-fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
- // Destructors only work on local ADT types.
- match tcx.type_of(impl_did).kind() {
- ty::Adt(def, _) if def.did().is_local() => return,
- ty::Error(_) => return,
- _ => {}
- }
-
- let sp = match tcx.hir().expect_item(impl_did).kind {
- ItemKind::Impl(ref impl_) => impl_.self_ty.span,
- _ => bug!("expected Drop impl item"),
- };
-
- tcx.sess.emit_err(DropImplOnWrongItem { span: sp });
-}
-
-fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
- debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
-
- let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
-
- let self_type = tcx.type_of(impl_did);
- debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);
-
- let span = tcx.hir().span(impl_hir_id);
- let param_env = tcx.param_env(impl_did);
- assert!(!self_type.has_escaping_bound_vars());
-
- debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
-
- let cause = traits::ObligationCause::misc(span, impl_hir_id);
- match can_type_implement_copy(tcx, param_env, self_type, cause) {
- Ok(()) => {}
- Err(CopyImplementationError::InfrigingFields(fields)) => {
- let item = tcx.hir().expect_item(impl_did);
- let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref tr), .. }) = item.kind {
- tr.path.span
- } else {
- span
- };
-
- let mut err = struct_span_err!(
- tcx.sess,
- span,
- E0204,
- "the trait `Copy` may not 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![];
-
- for (field, ty) in fields {
- let field_span = tcx.def_span(field.did);
- let field_ty_span = match tcx.hir().get_if_local(field.did) {
- Some(hir::Node::Field(field_def)) => field_def.ty.span,
- _ => field_span,
- };
- err.span_label(field_span, "this field does not implement `Copy`");
- // Spin up a new FulfillmentContext, so we can get the _precise_ reason
- // why this field does not implement Copy. This is useful because sometimes
- // it is not immediately clear why Copy is not implemented for a field, since
- // all we point at is the field itself.
- tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
- for error in traits::fully_solve_bound(
- &infcx,
- traits::ObligationCause::dummy_with_span(field_ty_span),
- param_env,
- ty,
- tcx.lang_items().copy_trait().unwrap(),
- ) {
- 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::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),
- ));
- }
- }
- }
- });
- }
- 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)
- }),
- );
- err.emit();
- }
- Err(CopyImplementationError::NotAnAdt) => {
- let item = tcx.hir().expect_item(impl_did);
- let span =
- if let ItemKind::Impl(ref impl_) = item.kind { impl_.self_ty.span } else { span };
-
- tcx.sess.emit_err(CopyImplOnNonAdt { span });
- }
- Err(CopyImplementationError::HasDestructor) => {
- tcx.sess.emit_err(CopyImplOnTypeWithDtor { span });
- }
- }
-}
-
-fn visit_implementation_of_coerce_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) {
- debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
-
- // Just compute this for the side-effects, in particular reporting
- // errors; other parts of the code may demand it for the info of
- // course.
- let span = tcx.def_span(impl_did);
- tcx.at(span).coerce_unsized_info(impl_did);
-}
-
-fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) {
- debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
-
- let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
- let span = tcx.hir().span(impl_hir_id);
-
- let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span));
-
- let source = tcx.type_of(impl_did);
- assert!(!source.has_escaping_bound_vars());
- let target = {
- let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
- assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
-
- trait_ref.substs.type_at(1)
- };
-
- debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target);
-
- let param_env = tcx.param_env(impl_did);
-
- let create_err = |msg: &str| struct_span_err!(tcx.sess, span, E0378, "{}", msg);
-
- tcx.infer_ctxt().enter(|infcx| {
- let cause = ObligationCause::misc(span, impl_hir_id);
-
- use rustc_type_ir::sty::TyKind::*;
- match (source.kind(), target.kind()) {
- (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
- if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {}
- (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (),
- (&Adt(def_a, substs_a), &Adt(def_b, substs_b))
- if def_a.is_struct() && def_b.is_struct() =>
- {
- if def_a != def_b {
- let source_path = tcx.def_path_str(def_a.did());
- let target_path = tcx.def_path_str(def_b.did());
-
- create_err(&format!(
- "the trait `DispatchFromDyn` may only be implemented \
- for a coercion between structures with the same \
- definition; expected `{}`, found `{}`",
- source_path, target_path,
- ))
- .emit();
-
- return;
- }
-
- if def_a.repr().c() || def_a.repr().packed() {
- create_err(
- "structs implementing `DispatchFromDyn` may not have \
- `#[repr(packed)]` or `#[repr(C)]`",
- )
- .emit();
- }
-
- let fields = &def_a.non_enum_variant().fields;
-
- let coerced_fields = fields
- .iter()
- .filter(|field| {
- let ty_a = field.ty(tcx, substs_a);
- let ty_b = field.ty(tcx, substs_b);
-
- if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
- if layout.is_zst() && layout.align.abi.bytes() == 1 {
- // ignore ZST fields with alignment of 1 byte
- return false;
- }
- }
-
- if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) {
- if ok.obligations.is_empty() {
- create_err(
- "the trait `DispatchFromDyn` may only be implemented \
- for structs containing the field being coerced, \
- ZST fields with 1 byte alignment, and nothing else",
- )
- .note(&format!(
- "extra field `{}` of type `{}` is not allowed",
- field.name, ty_a,
- ))
- .emit();
-
- return false;
- }
- }
-
- return true;
- })
- .collect::<Vec<_>>();
-
- if coerced_fields.is_empty() {
- create_err(
- "the trait `DispatchFromDyn` may only be implemented \
- for a coercion between structures with a single field \
- being coerced, none found",
- )
- .emit();
- } else if coerced_fields.len() > 1 {
- create_err(
- "implementing the `DispatchFromDyn` trait requires multiple coercions",
- )
- .note(
- "the trait `DispatchFromDyn` may only be implemented \
- for a coercion between structures with a single field \
- being coerced",
- )
- .note(&format!(
- "currently, {} fields need coercions: {}",
- coerced_fields.len(),
- coerced_fields
- .iter()
- .map(|field| {
- format!(
- "`{}` (`{}` to `{}`)",
- field.name,
- field.ty(tcx, substs_a),
- field.ty(tcx, substs_b),
- )
- })
- .collect::<Vec<_>>()
- .join(", ")
- ))
- .emit();
- } else {
- let errors = traits::fully_solve_obligations(
- &infcx,
- coerced_fields.into_iter().map(|field| {
- predicate_for_trait_def(
- tcx,
- param_env,
- cause.clone(),
- dispatch_from_dyn_trait,
- 0,
- field.ty(tcx, substs_a),
- &[field.ty(tcx, substs_b).into()],
- )
- }),
- );
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- }
-
- // Finally, resolve all regions.
- let outlives_env = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
- }
- }
- _ => {
- create_err(
- "the trait `DispatchFromDyn` may only be implemented \
- for a coercion between structures",
- )
- .emit();
- }
- }
- })
-}
-
-pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo {
- debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
-
- // this provider should only get invoked for local def-ids
- let impl_did = impl_did.expect_local();
- let span = tcx.def_span(impl_did);
-
- 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 source = tcx.type_of(impl_did);
- let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
- assert_eq!(trait_ref.def_id, coerce_unsized_trait);
- let target = trait_ref.substs.type_at(1);
- debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
-
- let param_env = tcx.param_env(impl_did);
- assert!(!source.has_escaping_bound_vars());
-
- let err_info = CoerceUnsizedInfo { custom_kind: None };
-
- debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
-
- tcx.infer_ctxt().enter(|infcx| {
- let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
- let cause = ObligationCause::misc(span, impl_hir_id);
- let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
- mt_b: ty::TypeAndMut<'tcx>,
- mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
- if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) {
- infcx
- .report_mismatched_types(
- &cause,
- mk_ptr(mt_b.ty),
- target,
- ty::error::TypeError::Mutability,
- )
- .emit();
- }
- (mt_a.ty, mt_b.ty, unsize_trait, None)
- };
- let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) {
- (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
- infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
- let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
- let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
- check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
- }
-
- (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => {
- let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
- check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
- }
-
- (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => {
- check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
- }
-
- (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b))
- if def_a.is_struct() && def_b.is_struct() =>
- {
- if def_a != def_b {
- let source_path = tcx.def_path_str(def_a.did());
- let target_path = tcx.def_path_str(def_b.did());
- struct_span_err!(
- tcx.sess,
- span,
- E0377,
- "the trait `CoerceUnsized` may only be implemented \
- for a coercion between structures with the same \
- definition; expected `{}`, found `{}`",
- source_path,
- target_path
- )
- .emit();
- return err_info;
- }
-
- // Here we are considering a case of converting
- // `S<P0...Pn>` to S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
- // which acts like a pointer to `U`, but carries along some extra data of type `T`:
- //
- // struct Foo<T, U> {
- // extra: T,
- // ptr: *mut U,
- // }
- //
- // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
- // to `Foo<T, [i32]>`. That impl would look like:
- //
- // impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
- //
- // Here `U = [i32; 3]` and `V = [i32]`. At runtime,
- // when this coercion occurs, we would be changing the
- // field `ptr` from a thin pointer of type `*mut [i32;
- // 3]` to a fat pointer of type `*mut [i32]` (with
- // extra data `3`). **The purpose of this check is to
- // make sure that we know how to do this conversion.**
- //
- // To check if this impl is legal, we would walk down
- // the fields of `Foo` and consider their types with
- // both substitutes. We are looking to find that
- // exactly one (non-phantom) field has changed its
- // type, which we will expect to be the pointer that
- // is becoming fat (we could probably generalize this
- // to multiple thin pointers of the same type becoming
- // fat, but we don't). In this case:
- //
- // - `extra` has type `T` before and type `T` after
- // - `ptr` has type `*mut U` before and type `*mut V` after
- //
- // Since just one field changed, we would then check
- // that `*mut U: CoerceUnsized<*mut V>` is implemented
- // (in other words, that we know how to do this
- // conversion). This will work out because `U:
- // Unsize<V>`, and we have a builtin rule that `*mut
- // U` can be coerced to `*mut V` if `U: Unsize<V>`.
- let fields = &def_a.non_enum_variant().fields;
- let diff_fields = fields
- .iter()
- .enumerate()
- .filter_map(|(i, f)| {
- let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
-
- if tcx.type_of(f.did).is_phantom_data() {
- // Ignore PhantomData fields
- return None;
- }
-
- // Ignore fields that aren't changed; it may
- // be that we could get away with subtyping or
- // something more accepting, but we use
- // equality because we want to be able to
- // perform this check without computing
- // variance where possible. (This is because
- // we may have to evaluate constraint
- // expressions in the course of execution.)
- // See e.g., #41936.
- if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) {
- if ok.obligations.is_empty() {
- return None;
- }
- }
-
- // Collect up all fields that were significantly changed
- // i.e., those that contain T in coerce_unsized T -> U
- Some((i, a, b))
- })
- .collect::<Vec<_>>();
-
- if diff_fields.is_empty() {
- struct_span_err!(
- tcx.sess,
- span,
- E0374,
- "the trait `CoerceUnsized` may only be implemented \
- for a coercion between structures with one field \
- being coerced, none found"
- )
- .emit();
- return err_info;
- } else if diff_fields.len() > 1 {
- let item = tcx.hir().expect_item(impl_did);
- let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) =
- item.kind
- {
- t.path.span
- } else {
- tcx.def_span(impl_did)
- };
-
- struct_span_err!(
- tcx.sess,
- span,
- E0375,
- "implementing the trait \
- `CoerceUnsized` requires multiple \
- coercions"
- )
- .note(
- "`CoerceUnsized` may only be implemented for \
- a coercion between structures with one field being coerced",
- )
- .note(&format!(
- "currently, {} fields need coercions: {}",
- diff_fields.len(),
- diff_fields
- .iter()
- .map(|&(i, a, b)| {
- format!("`{}` (`{}` to `{}`)", fields[i].name, a, b)
- })
- .collect::<Vec<_>>()
- .join(", ")
- ))
- .span_label(span, "requires multiple coercions")
- .emit();
- return err_info;
- }
-
- let (i, a, b) = diff_fields[0];
- let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
- (a, b, coerce_unsized_trait, Some(kind))
- }
-
- _ => {
- struct_span_err!(
- tcx.sess,
- span,
- E0376,
- "the trait `CoerceUnsized` may only be implemented \
- for a coercion between structures"
- )
- .emit();
- return err_info;
- }
- };
-
- // Register an obligation for `A: Trait<B>`.
- let cause = traits::ObligationCause::misc(span, impl_hir_id);
- let predicate = predicate_for_trait_def(
- tcx,
- param_env,
- cause,
- trait_def_id,
- 0,
- source,
- &[target.into()],
- );
- let errors = traits::fully_solve_obligation(&infcx, predicate);
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- }
-
- // Finally, resolve all regions.
- let outlives_env = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
-
- CoerceUnsizedInfo { custom_kind: kind }
- })
-}